6

If I call a constructor on an already constructed object or struct, will it allocate new space, or just use the existing space? So is the first object allocation more resource intensive? Like this:

struct F {
    int a,b,c,d;
    F(int _a, int _b) {a = _a; b = _b}; 
    void a(int _a, int _b) {a = _a; b = _b};
};  

//first constructor call
F f = F(5, 6);

//second constructor call on an already constructed object
f = F(7, 8);

//third constructor call on an already constructed object
f(7, 8);

//is the constructor call more res. intesive, than the call to a function which does the same? 
f.a(9, 0)

Is the constructor call more resource intesive, than the call to a function which does the same (void a(...))?

Does the destructor gets called, when I call a constructor on an already created object?

Keith Pinson
  • 7,835
  • 7
  • 61
  • 104
Peter Lapisu
  • 19,915
  • 16
  • 123
  • 179

5 Answers5

8

First off, the [c] tag is inappropriate since constructors are a C++-only feature. I'll assume the code snippet you provided is in fact C++ and not some weird dialect of C. C++ and C are different languages; do not tag your questions as both since you will get different answers for each.

Second, your constructor definition is wrong. Constructors must have the exact same name as the class itself. So f() should've been F(). Yes, case-sensitivity matters in C++! I'll assume this is what you meant for the rest of the code snippet. OP simply made a typo.

Before I explain what the rest of your code does, you must understand that all classes (and structs) in C++ have special member functions that are automatically generated by the compiler if you don't provide them. That is, your code snippet is basically the same as:

struct F
{
    F(int _a, int _b) {a = _a; b = _b};  // constructor
    ~F() {}                              // destructor
    F(const F& rhs)                      // copy constructor
        : a(rhs.a)
        , b(rhs.b)
        , c(rhs.c)
        , d(rhs.d)
    {}
    F& operator=(const F& a)             // copy assignment operator
    {
        a = rhs.a;
        b = rhs.b;
        c = rhs.c;
        d = rhs.d;
        return *this;
    }

    void a(int _a, int _b) {a = _a; b = _b};   // one of your functions

    int a;
    int b;
    int c;
    int d;
};

If you do not define a copy constructor, a copy assignment operator, or a destructor, the compiler will generate them for you. Also, if you don't provide some other constructor, the compiler will generate a default constructor. There is no default constructor for class F since there's already a (non-copy) constructor that accepts two arguments.

The default implementation of the copy constructor and the copy assignment operator simply copies each data member.

The reason why special member functions exist is because C++ generalizes the notion of copying primitive types to user defined objects. Consider this:

int a = 42;
int b = 13;
b = a;

With primitive types like ints, you can copy around its value just like that. C++ generalizes the copy semantics to objects so you can do this:

F f(10, 20); // calls first constructor
F g(30, 40); // calls first constructor
g = f;       // calls g's copy-assignment operator.

Now you can see how this applies to your code:

F f = F(5,6); 

The line above constructs a temporary F object, then copies the temporary into f via the copy constructor. The temporary F object is then destructed.

f = F(7,8);

The line above constructs another temporary F object, then assigns the temporary into f via the copy assignment operator. The temporary F object is then destructed. The original f object is not destructed.

f.a(9,0)   

The line above is a normal function call on an object called f.

For your code snippet, assuming compilers do not optimize away the temporaries (they in fact usually do), then calling the function a is "less resource intensive" since no temporaries are made in that case. However, for your first constructor call, you can just do this:

F f(5,6); // Constructor called; no temporaries are made

Understand what constructors are used for: they are used to create objects. If you already have an object, then you don't need to call a constructor.

As I have recommended many times, please pick up a good C++ book and read it. Special member functions and what they do are quite fundamental to C++.

Community
  • 1
  • 1
In silico
  • 51,091
  • 10
  • 150
  • 143
  • Typo. Change `f = f(7,8);` to `f = F(7,8)` in the second constructor call statement . – Mahesh Feb 18 '11 at 08:28
  • @Mahesh: Thanks for catching that. – In silico Feb 18 '11 at 08:31
  • Also, there should be a constructor that takes two integer arguments in the `F` definition. Else it won't compile. – Mahesh Feb 18 '11 at 08:31
  • ok, so doing F f = F(5,6); is more resource intensive than doing F f(5,6); because it involves the copy operator, but can i suggest that if i call f(5,6); than it is same resource intensive as f.a(5,6) ? thank you – Peter Lapisu Feb 18 '11 at 08:35
  • 1
    @Peter Lapisu: Not exactly. `F f(5, 6)` causes the stack to allocate enough space to store your `f` object (i.e. the `f` object is pushed onto the stack). The function call doesn't need to push anything since an `f` object already exists (althought a stack frame will be pushed onto the stack if it isn't inlined). For your specific code snippet you provided, the constructor and function `a()` does almost the same thing, so there isn't much of a difference. But it is possible that the constructor and `a()` do completely different things with respect to memory usage. – In silico Feb 18 '11 at 08:52
  • Suppose I have an already constructed object of type F, called ff (let's say that I initially constructed it with the line `F ff(5, 5);`) and I want to change all its member variables exactly like `ff.a(10, 10);` would do. Could I just do `ff(10, 10);` and do away with the F::a(int, int) member function? – nitsas Feb 07 '13 at 16:53
  • To answer my own question (previous comment): No, you could not just call ff(10, 10) instead of ff.a(10, 10) because if you could and your F class had an F::operator()(int, int) how would the compiler know if you wanted to call F's constructor or F's () operator? – nitsas Feb 18 '13 at 19:23
4

(In the code you posted you've used a lower-case f instead of an upper-case F for the constructor, which I assume is a typo)

Your question is interesting because the question you've asked and the code you've written are not the same. In the code, you've written

f = F(7, 8);

This does call the F constructor, but not on the existing f object. Instead, this creates a temporary F object initialized by calling tue constructor with 7 and 8 as arguments, then uses the assignment operator to set the existing f variable equal to this new object. Consequently, the constructor is not invoked twice on the object; instead it's the assignment that gets called here. More generally, if you ever assign an existing object a new value, the assignment operator, not a constructor, will be used to do the copying. This will reuse the existing memory for the object, though it may trigger auxiliary memory allocations and deallocations.

There is no safe way to invoke an object's constructor twice. If you really do want to invoke the constructor of an object that's already been created, you can do so using placement new:

F f(3, 5);
new (&f) F(7, 9);

This is unsafe as it bypasses typical resource cleanup the destructors normally would do and blindly overrides the existing elements, so this is almost never done in practice. I mention it mostly for the sake of curiosity and for completeness. :-)

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • +1 cause you went right at the point of the question! Calling a constructor on a already existing object in order to reinitialise it seems to be a pretty common mistake (I was trying to do the same), especially in beginners! – Matteo Mar 31 '12 at 09:13
  • Still I have a doubt. Suppose you have a member object you construct within class constructor of another class, and in one of member functions you want to completely reconstruct it with new values (using its constructor), how would you do that if you haven't overloaded the `=` operator? – Matteo Mar 31 '12 at 09:20
  • @Matteo, I believe that `f.F::F(8, 9);` will reconstruct the object by calling the constructor on the already existing object. – ThomasMcLeod Jul 05 '12 at 23:38
2

i'm ignoring the implementation in the OP, and going straight to the QA:

if i call a constructor on an already constructed object / struct, will it allocate new space

no, the object will not be reallocated. the constructor's implementation will be called (e.g. a function call).

So is the first object allocation more resource intensive?

you should generally not do this, unless you're implementing a collection (e.g. vector).

but, to answer the question: yes, the second will require fewer instructions. the compiler produces trivial instructions to set up the allocation (if on the stack or elsewhere). so there really is a few stages to creating an object automatically, and you are bypassing some of that. but seriously: don't consider this as an optimization -- only call the constructor/destructor manually if you absolutely must (again, think collection types).

Is the constructor call more res. intesive, than the call to a function which does the same (void a(...)) ?

potentially, the compiler's efforts also weigh in. remember, constructors and destructors call the implementation of each class in the hierarchy, so... it's quite likely that a singular function would be faster if your class hierarchy is non-trivial.

Does the destructor gets called, when i call a constructor on an already created object?

if you explicitly construct an object in this manner, then the answer is 'no'. it's your job to appropriately pair the explicit invocations. you cannot afford to implement this incorrectly, it's as good as UB. the order is always construct->destruct.

just to be clear of the syntax used:

// explicit ctor
new(ptr) T(ctorArgument);
// explicit dtor
ptr->~T();
justin
  • 104,054
  • 14
  • 179
  • 226
1

There are syntatic mistakes in your program, modifying your snippet-

struct F {

    int a,b,c,d;

    F(int _a, int _b) {a = _a; b = _b}; 

    void a(int _a, int _b) {a = _a; b = _b};

};

F f = F(5,6); // Here the default copy constructor gets called.
              // i.e., F( const F& obj ) ;

f = F(7,8);   // A temporary is created is assigned to `f` through default copy assignment operator.
              // i.e., F& operator=( const F& obj );

Destructor gets called, when the constructed object goes out of scope ( ie., when the life time of the object completes).

Mahesh
  • 34,573
  • 20
  • 89
  • 115
0

Your class F does not have a constructor but only a method f. So, no constructor is called at any time.

harper
  • 13,345
  • 8
  • 56
  • 105