deleyd
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
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?
File: ClassA.h
#pragma once
#include "ClassB.h"
class ClassA
{
public:
ClassA(void);
~ClassA(void);
private:
ClassB myClassB;
};
File: ClassA.cpp
#include "StdAfx.h"
#include "ClassA.h"
ClassA::ClassA(void)
{
myClassB = ClassB(12);
}
ClassA::~ClassA(void)
{
}
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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")
http://www.cprogramming.com/tutorial/initialization-lists-c++.html ("Understanding Initialization Lists in C++")
http://www.efnetcpp.org/wiki/Constructor_Initializer ("Constructor Initializer")
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
File ClassA.h
#pragma once
#include "ClassB.h"
#include "ClassC.h"
class ClassA
{
public:
ClassA(void);
~ClassA(void);
private:
ClassB myClassB;
ClassC myClassC;
};
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)
{
}
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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.
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.
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
Then in the destructor I release that mutex:
CloseHandle(ghMutex);
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Will declaring the integer and float variables volatile be sufficient to make them multithreaded safe?
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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?
Do I also need a protected read function? Or is the protected write function enough?
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thank you very much. One more question,
The syntax is confusing.
ClassA::ClassA(void) : myClassB(), myClassC(myClassB) // 'myClassB' here just serves the purpose to enforce the construction before 'myClassC'
{
//further lines...
}
In this initializer list list it looks like we're storing myClassB in variable myClassC.The syntax is confusing.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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); }
};
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) { }
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) {}
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
ASKER