Solved

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

Posted on 2014-01-02
16
319 Views
Last Modified: 2014-01-07
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?
0
Comment
Question by:deleyd
16 Comments
 
LVL 142

Accepted Solution

by:
Guy Hengel [angelIII / a3] earned 72 total points
ID: 39751776
the explanation is this:

private:
  ClassB myClassB;

will already create a class variable.
then, in the constructor of classA, you create and assign a NEW class variable, and assign it.
by that, the reference to the initially created object will get "out of scope", and hence the desctructor will be called.

the result is that your variables are all fine.

the only difference you may do is that instead of creating a new classB variable (and hence use it's constructor method), you could define a method to "reinitialize" the classB properties based on the input...
0
 

Author Comment

by:deleyd
ID: 39751836
Is there a way to do this without creating the first ClassB instance which is later thrown away?
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 428 total points
ID: 39751873
>>Is there a way to do this without creating the first ClassB instance which is later thrown
>>away?

Yes, do that in the constructor initializer list:

ClassA::ClassA(void) : myClassB(12)
{
  // that's it!
}

Open in new window

0
 
LVL 86

Expert Comment

by:jkr
ID: 39751877
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")
0
 

Author Comment

by:deleyd
ID: 39752043
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?
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 428 total points
ID: 39752105
You can do that the same way:

ClassA::ClassA(void) : myClassB(), myClassC(myClassB) // 'myClassB' here just serves the purpose to enforce the construction before 'myClassC'
{
 
  //further lines...
}

Open in new window

0
 

Author Comment

by:deleyd
ID: 39752131
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.
0
 

Author Comment

by:deleyd
ID: 39752174
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?
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 86

Assisted Solution

by:jkr
jkr earned 428 total points
ID: 39752195
Since you are using multithreading in a single process only, a CRITICAL_SECTION (http://msdn.microsoft.com/en-us/library/windows/desktop/ms682530(v=vs.85).aspx) should suit your needs better and is less of a performance penalty. But: If it's really just about integers, 'InterlockedExchange()' (http://msdn.microsoft.com/en-us/library/windows/desktop/ms683590(v=vs.85).aspx) would be the API of choice.
0
 

Author Comment

by:deleyd
ID: 39752315
Will declaring the integer and float variables volatile be sufficient to make them multithreaded safe?
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 428 total points
ID: 39752329
No, definitely not. 'volatile' only affects compiler-generated optimizationbs, see http://msdn.microsoft.com/en-us/library/vstudio/12a04hfd%28v=vs.110%29.aspx ("volatile (C++)").

BTW: Wile it nowadays (on x86 CPUs) might not be necessary to guard integers between threads, I'd never recommend such a practise. In a multithreaded environment, always synchronize variable access.
0
 

Author Comment

by:deleyd
ID: 39752572
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?
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 428 total points
ID: 39752617
Again: The 'Interlocked*()' functions are for integers only. For everything else that happens within one process' context, a CRITICAL_SECTION suits you better. BTW, you will find a really nice and useful class encapsulation for these at http://scriptionary.com/2008/08/22/criticalsection-wrapper-class/

>>Do I also need a protected read function? Or is the protected write function enough?

Good question - in practise and on x86, it'd probably be enough to write-sync integrl types. Yet I'd still recommend to also sync read access, since it's simply cleaner. Furthermore, once you developed a habit for that, you won't accidentially write sloppy parallel code in the future,
0
 

Author Comment

by:deleyd
ID: 39752784
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.
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 428 total points
ID: 39752997
Yes, it is - but it seems that you needed 'myClassB' as an argument to the constructor of 'myClassC', so that's why it is done this way. it is the equivalent to your code, just that all this takes place before the actual body of the ctor of 'ClassA' is called, thus avoiding all these temporary objects, duplicates and assignments.
0
 
LVL 32

Expert Comment

by:sarabande
ID: 39759461
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
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
Unlike C#, C++ doesn't have native support for sealing classes (so they cannot be sub-classed). At the cost of a virtual base class pointer it is possible to implement a pseudo sealing mechanism The trick is to virtually inherit from a base class…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now