views:

1727

answers:

7

After creating a instance of a class, can we invoke the constructor explicitly? For example

class A{
    A(int a)
    {
    }
}

A instance;

instance.A(2);

Can we do this?

+10  A: 

You can use placement new: http://en.wikipedia.org/wiki/Placement_new which permits

new (&instance) A(2);

However, from your example you'd be calling a constructor on an object twice which is very bad practice. Instead I'd recommend you just do

A instance(2);

Placement new is usually only used when you need to preallocate the memory e.g. in a custom memory manager.

Michael
@Michael: what does it have to do with it? It is a low-level thing...and a new object will be created anyway, just over the old one, am I wrong?
badbadboy
Hope my edit makes it clearer.
Michael
I've +1'd this answer - but I disagree with the point about using this in the special case of pre-allocating memory. Anyway, in this instance, the 'instance' object *is* the pre-allocated memory.
Richard Corden
As said placement new is intended to be used with uninitialized memory. Consider a string constructor for instance, it might allocate buffer space for an empty string; if you call another constructor, it will allocate again and you have a memory leak.
Mark Ransom
+2  A: 

I am pretty sure you can't do that. That's the whole point, constructor IS creation of an instance of the class.

If a constructor is not called at all, or is called twice - which consequences could it have?

What you could do of course, is extracting some constructor logic into the method, and calling that method both in the constructor and after creation of the object.

badbadboy
right - you shouldn't ever be able to call a constructor 'directly', except in @Michael's method of the "placement new" - but even that's not something you're normally going to see :)
warren
+7  A: 

No.

Create a method for the set and call it from the constructor. This method will then also be available for later.

class A{
    A(int a) { Set(a); }
    void Set(int a) { }
}

A instance;

instance.Set(2);

You'll also probably want a default value or default constructor.

brofield
It is possible - placement new does exactly what the OP wanted.
Richard Corden
True, but even though this is what OP asked for, it's almost certianly not the Right Thing.
John Dibling
+3  A: 

No

Calling instance.A() or A(1) is seens as casting  'function-style cast' : illegal as right side of '.' operator

Usually if a function/functionality is to needed in constructor as well as after object is construted it is placed in init() methode and used in constructor and in other place too.

example:

 class A{
      A(int a)
       { 
        init(a);
       }

     void init(int a) { } 
     }

        A instance;

        instance.init(2);
yesraaj
A: 

Just to summarize, the three ways to specify the explicit constructor are via

  1. A instance(2); // does A instance = 2; ever work?

  2. A *instance = new A(2); //never sure about & versus * here, myself

  3. new (&instance) A(2);

and flavors of those. The idea goal is to arrange that at no time is an object constructed that is not in a proper initialized state, and constructors are designed to assure that. (This means that methods don't have to check on whether some .init(...) method has been successfully called or not.)

This strikes me as the more-functional way to go about this, especially for classes that are parts of frameworks and reused in libraries. If that is what you are interested in, work toward having all constructors, including any default one, deliver a fully-working instance.

Exception Cases: There are things you might not have in the constructor operation if it is possible for them to fail, unless it is appropriate to throw an exception from the constructor. And some folks like having "blank" instances that are propogated using subsequent methods and even exposed-to-initialization members. It is interesting to explore ways to mitigate such situations and have robust instances that don't have bad states that need to be protected against in method implementations and in usage.

PS: In some complex cases, it may be useful to have an initialized instance (reference) be delivered as the result of a function or of a method on a "factory" class, so that the intermediate, under-setup instance is never seen outside of the encapsulating factory class instance or function. That gives us,

+4. A *instance = MakeAnA(2);

+5. A *instance = InterestingClass.A(2);

orcmid
Konrad Rudolph
If the object can be in an uninitialized state in (2) then isn't the same problem possible in (1) and (3)? I would assume that the only way (2) fails (assuming that the constructor is designed to do a good job) is if memory allocation fails, and that makes instance == NULL.
orcmid
A: 

By the way, this sounds like a design flaw. Once an object is constructed there should never be a need to re-construct it. Such variable name reuse makes the code rather harder to understand. For that reason, making constructor-like functionality available through an extra function init or set is often wrong (but sometimes unavoidable).

As Michael said, placement new could be used here but is really intended for different uses. Also, before constructing a new object in a memory location, you have to explicitly destroy the old object:

instance.~A();

Also, placement new can have an averse effect on your memory because overloads might expect that the memory it is passed belongs to the heap! In conclusion: don’t. do. this.

EDIT To demonstrate that calling the destructor is really necessary (for non-POD), consider the following example code:

#include <iostream>

struct A {
    A(int a) { std::cerr << "cons " << a << std::endl; }
    ~A() { std::cerr << "dest" << std::endl; }
};

int main() {
    A instance(2);
    new (&instance) A(3);
}

As expected, the program results in the following output:

cons 2
cons 3
dest

… which means that the destructor for the first object is not called. The same goes for any resources that A might have acquired.

Konrad Rudolph
konrad, you don't have to: "For an object of a class type with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released". Whether or not this is also true of objects with trivial dtors, i don't now
Johannes Schaub - litb
i would suspect it's true for those true. Wouldn't make sense to forbid that there, but allow that for non-trivials
Johannes Schaub - litb
@litb, please elaborate. I presume that you're misunderstanding a passage that doesn't apply to explicit constructor invocation through `placement new` because the destructor is most definitely *not* called automatically but *has* to be called manually (see update to my posting).
Konrad Rudolph
I think it does. It says when your program is not depending on the side effects, you are not required to call the destructor. Otherwise, if it depends on those effects, your program does invoke undefined behavior.
Johannes Schaub - litb
(i think it does) =>i think it does talk about explicit creating a new object there, thus reusing its storage. (i copied it verbatimly from the standard. you can search for that text. it's in the "Objects Lifetime" paragraph)
Johannes Schaub - litb
in your test program you depend on the fact that your dtor prints "dest". thus in that case it is UB. but if your program prints something, and you can live with not seeing it, you don't have UB.
Johannes Schaub - litb
(actually placement new is the only mechanism that can reuse the storage that some object occupies. the standard even uses this in that paragraph in examples. look it up :))
Johannes Schaub - litb
Ok, in other words (and what I thought): RAII doesn't work here. Isn't this effectively tantamount to saying that manual destructing *is* required here? It just states that the C++ runtime (i.e. the memory management) mustn't depend on the destructor being called.
Konrad Rudolph
all i know is that the program must not depend on the constructors' side effects, if it omits calling it explicitly. if so, it is allowed to omit it. but i agree that it's always the best to call it, and naughty not doing so.
Johannes Schaub - litb
A: 

No you cannot do that. The only way to invoke a constructor is by the keyword "new".