Can you invoke an instantiated object's class constructor explicity in C++?

前端 未结 7 2215
逝去的感伤
逝去的感伤 2020-12-31 15:17

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);
         


        
相关标签:
7条回答
  • 2020-12-31 15:26

    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);

    0 讨论(0)
  • 2020-12-31 15:27

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

    0 讨论(0)
  • 2020-12-31 15:28

    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.

    0 讨论(0)
  • 2020-12-31 15:29

    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.

    0 讨论(0)
  • 2020-12-31 15:32

    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.

    0 讨论(0)
  • 2020-12-31 15:41

    You can use 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 pre-allocate the memory (e.g. in a custom memory manager) and construct the object later.

    0 讨论(0)
提交回复
热议问题