views:

358

answers:

4

I have been reviewing some code that looks like this:

class A; // defined somewhere else, has both default constructor and A(int _int) defined
class B
{
public:
    B(); // empty
    A a;
};

int main()
{
     B* b;
     b = new B();
     b->a(myInt); // here, calling the A(int _int) constructor,
     //but default constructor should already have been called
}

Does this work? Calling a specific constructor after the default has already been called?

+14  A: 

That code does not call a's constructor. It calls A::operator()(int).

But if you explicitly call a constructor on an object that has already been constructed, you're well into undefined behavior-land. It may seem to work in practice, but there is no guarantee that it'll do what you expect.

jalf
This appears to be the case, thank you.
It only calls "A::operator()(int)" if that function is declared? I'm impressed you were able to determine that this function was declared!
Richard Corden
@Richard: I'm not sure what you're getting at. If the function was not declared, the code wouldn't compile. So assuming that the code *does* compile, that means that the operator must be defined.There is no ambiguity. The syntax used can *never* call a constructor, if that's what you're getting at. To do that, you would have to write b->a::A(myInt) instead. The syntax shown in Rich's question can *only* call operator().
jalf
"write b->a::A(myInt)" Is this legal C++? Certainly doesn't compile on my compiler.I may be wrong here, but as far as I know, there is no way to call an object's constructor except when it is created or via placement new. Anything that manages to explicitly call a class's constructor actually creates a temporary first.
Ari
I wasn't getting at anything. I am aware that you cannot call the constructor like this, I missed the bit about him reviewing the code, so yes - as you say if the code compiles the class must have a functor declared.
Richard Corden
Ari: You're right, I screwed up the syntax. It should have been "b->a.A::A(myInt)". (And even that is obviously very rarely valid or meaningful.)
jalf
just to be clear about this one, yes there was a function operator() declared that was part of a superclass of A, I didn't see it until I went to look for it by jalf's suggestion.
+1  A: 

This is not calling the constructor, and this answer covers the only possible explanation for what is happening.

The only standard way to call a constructor on an existing object is to use placement new, (after the previous instance has been destructed):

void foo (A * a) {
  a->~A ();           // Destroy previous instance
  new (a) A(myInt);   // Construct new object in same location
}
Richard Corden
Placement new might be dangerous in case the constructor has side effects (e.g., counting the number of live objects). It is best left for its intended purpose of replacing the default memory management system.
Ari
@Ari. Sure. But it's the only way to call a constructor on an already constructed object (if that's what you intend to do).
Richard Corden
Actually, you have to first unconstruct the object: b->a.~A(); before the placement new. Placement new only works on raw, aligned memory.
MSalters
+1  A: 

you can make another constructor in Class B

B(int _int):a(_int) {}

in that case when you write b = new B(myInt);

Above code will not delay your constructor code of class A.

you dont need to call b->a(myInt)

Syed Tayyab Ali
It's not legal C++. You should remove "Yes it will work" from your answer, or you may get marked down.
Richard Corden
@Richard Corden: done
Syed Tayyab Ali
I don't see any ilegal C++ in this comment
piotr
Earlier I said that code in the question will run. but after Richard Corden correct me, then I edited my reply. It is Ok now. Therefore, you are not seeing any incorrect code.
Syed Tayyab Ali
A: 

You should just call the A(int) constructor from within the B() constructor or make a B(int) constructor that also calls the A(int) one.

The best practice is to have both, the default one to setup a default int for A, and the B(int) one to init A(int).

Azder