Link to home
Start Free TrialLog in
Avatar of deleyd
deleydFlag for United States of America

asked on

C++ syntax; Instantiating a class with parameters; constructor run order

I would like to have a ClassA, which holds within it an instance of ClassB. The instance of ClassB is created with a parameter. Something about the following code isn't doing what I expect.

File: ClassA.h
#pragma once
#include "ClassB.h"

class ClassA
{
public:
  ClassA(void);
  ~ClassA(void);
private:
  ClassB myClassB;
};

Open in new window

File: ClassA.cpp
#include "StdAfx.h"
#include "ClassA.h"

ClassA::ClassA(void)
{
  myClassB = ClassB(12);
}


ClassA::~ClassA(void)
{
}

Open in new window

What I see happening when I test this, is ClassA.h line 10 is creating an instance of ClassB with no parameters. Then ClassA.cpp line 6 is creating another instance of ClassB with parameter 12, the ClassB constructor is called which handles the parameter 12, then when the ClassA constructor exists, the destructor for ClassB is called, indicating the class I just created is being deleted.

I'm left with myClassA pointing to my instance of ClassB created with the parameter 12, but I suspect that class has already been deleted, and there's another instance of ClassB floating around somewhere that was created with no parameters?

Or perhaps that's not what is happening and I need an explanation of what is happening.

What's the syntax for doing what I want, which is create an instance of ClassB with a parameter, and hold on to that class?
ASKER CERTIFIED SOLUTION
Avatar of Guy Hengel [angelIII / a3]
Guy Hengel [angelIII / a3]
Flag of Luxembourg image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of deleyd

ASKER

Is there a way to do this without creating the first ClassB instance which is later thrown away?
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
BTW, some more reading and info about initializer lists:

http://www.cprogramming.com/tutorial/initialization-lists-c++.html ("Understanding Initialization Lists in C++")
http://www.efnetcpp.org/wiki/Constructor_Initializer ("Constructor Initializer")
Avatar of deleyd

ASKER

OK I have a slightly more complicated version. Instead of initializing an integer, I would like ClassA to create and save an instance of ClassC, and then create and save an instance of ClassB passing the instance of ClassC as the parameter.

File ClassA.h
#pragma once
#include "ClassB.h"
#include "ClassC.h"

class ClassA
{
public:
  ClassA(void);
  ~ClassA(void);
private:
  ClassB myClassB;
  ClassC myClassC;
};

Open in new window

File ClassA.cpp
#include "StdAfx.h"
#include "ClassA.h"
#include "ClassC.h"

ClassA::ClassA(void)
{
  myClassB = ClassB();
  myClassC = ClassC(myClassB);
  //further lines...
}


ClassA::~ClassA(void)
{
}

Open in new window

This is a stripped down version of my actual project. Something isn't going right in the initialization of my actual project. When it executes line 8 of ClassA.cpp it skips all further lines like there's some internal error. Anything wrong with this code?
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of deleyd

ASKER

I think my problem is I'm passing myClassB as a parameter (line 8 ClassA.cpp), and that's making a copy of myClassB, so I end up with two identical copies of myClassB.

I'm guessing the constructor for the copy of myClassB isn't being called, where I allocate a resource. So the destructor gets called for the original, then the copy, attempting to release the same resource a 2nd time.
Avatar of deleyd

ASKER

I wanted to synchronize access to a simple variable (integer or float), make it thread safe, so I allocate and save a mutex in the constructor of ClassB:
      ghMutex = CreateMutex( 
        NULL,              // default security attributes
        FALSE,             // initially not owned
        NULL);             // unnamed mutex

Open in new window

Then in the destructor I release that mutex:
CloseHandle(ghMutex);

Open in new window

Maybe there's a better way to synchronize access to an integer so I don't have two threads, one writing the other reading the variable at the same time?
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of deleyd

ASKER

Will declaring the integer and float variables volatile be sufficient to make them multithreaded safe?
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of deleyd

ASKER

How would I use InterlockedExchange to protect a float or a double?

Do I also need a protected read function? Or is the protected write function enough?
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of deleyd

ASKER

Thank you very much. One more question,
ClassA::ClassA(void) : myClassB(), myClassC(myClassB) // 'myClassB' here just serves the purpose to enforce the construction before 'myClassC'
{
 
  //further lines...
}

Open in new window

In this initializer list list it looks like we're storing myClassB in variable myClassC.

The syntax is confusing.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
How would I use InterlockedExchange to protect a float or a double?
there is a fast mutex class which uses the InterlockedIncrement and InterlockedDecrement to grant exclusive access to any other resource.

class FastMutex
{
      volatile long lock;
public:
      FastMutex() : lock(0) {}
 
     void enter() 
      {
         while (InterlockedIncrement(&lock) > 1)
         {
             InterlockedDecrement(&lock);
             Sleep(0);
         }
       }
       void leave() { InterlockedDecrement(&lock); }
};

Open in new window


the "interlocked" mode would guarantee that two threads would run one after the other and the second would be locked while the first thread does not release the lock.

note with the fast mutex a thread cannot call 'enter' twice without dead-locking. if that is an issue you should use a critical section instead which can be entered multiple times by the same thread (and needs a leave for each enter).


Anything wrong with this code?

hmmm. i don't know why you need 3 classes which mutually make a reference to each other. that actually adds complexity which is unnecessary in almost all cases. beside of avoiding redundancy, your class design needs to have clear responsibilities. a mutex is a helper only. it may not be the determining factor for a design. creating the mutex in the constructor and destroying it in the destructor is fine. the mutex should be a member of classA as it is the 'parent' class which was deleted after their class members. if those also should use the mutex you may provide a member function of classA which returns a reference to the mutex object and the sub classes classB and classC may hold a pointer to their parent which easily could be passed in classA constructor:

classA::classA() : myclassB(this), myClassC(this) { }

Open in new window


note, if your hierarchy is

classA -> classB -> classC

you would have myxclassB a member of classA and myClassC a member of classB. if additionally both classes clasB and classC should have access to their parents you would have a member pointer to classA in classB and a member pointer to classB in classC. the constructors would be like

classA::classA() : classB(this) {}

classB::classB(classA * pA) : pmyClassA(pA), myClassC(this) {}

classC::classC(classB * pB) : pmyClassB(pB) {}

Open in new window


here pointers are the better choice over references if you want to use classB and classC objects independently of a 'parent'. for those cases you would pass a NULL pointer.

myClassB = ClassB();
this statement makes no sense in a c++ constructor because the myClassB already was created before it was entering the constructor's. that is the reason why c++ has an initializer list outside of the constructor's body to initialize members and create class members with a non-default constructor. with the statement you made you create an additional temporary classB object and assign it to the already created myclassB object. if classB has a default constructor which correctly initializes all members that copy+assign doesn't make anything worse. but nevertheless it is not needed and error-prone. if myClassB was initialized with an existing member, the assignment would destroy the contents of the member and its origin.
     
Sara