0

Based on what I understand, resize method of the template class vector<class> uses the constructor without parameters to a create a new object, and then, uses copy constructor to clone the previous object. Indeed, this code prove it:

#include <iostream>
#include <vector>
using namespace std;
class A{
public:
    A(){
        cout << "Appel constructeur !" << endl;
        cout << this << endl;
    }
    A(const A &a){
        cout << "Appel constructeur de recopie" << endl;
        cout << this << endl;
    }
    ~A(){
        cout << "Appel destructeur !" << endl;
    }
};
int main() {
    vector<A> t;
    t.resize(2);
    cout << t.size() << endl;
    cout << &t[0] << endl;
    cout << &t[1] << endl;
}

The output is with mingw32-g++.exe:

Appel constructeur !
0x69fedf
Appel constructeur de recopie
0x905690
Appel constructeur de recopie
0x905691
Appel destructeur !
2
0x905690
0x905691
Appel destructeur !
Appel destructeur !

The output with g++ (it calls the constructor twice)

Appel constructeur !
0x55c91bff3e70
Appel constructeur !
0x55c91bff3e71
2
0x55c91bff3e70
0x55c91bff3e71
Appel destructeur !
Appel destructeur !

So my questions are: why create a new object then destroy it? why the first object created has an address very far from the other objects?

ThunderPhoenix
  • 1,649
  • 4
  • 20
  • 47
  • The resize method takes two parameters prior to C++11, so maybe you're compiling with an old version of C++? https://en.cppreference.com/w/cpp/container/vector/resize – Mooing Duck Dec 05 '19 at 23:11
  • Which compiler and compiler options do you use? In c++17, you should get two calls to constructor, and two to destructor. – ChrisMM Dec 05 '19 at 23:11
  • @ChrisMM I am using `mingw32-g++.exe` it is a recent version ! I think it is C++17 – ThunderPhoenix Dec 05 '19 at 23:16
  • When you `resize` to two, it should call the constructor twice. Unless it's previous size was 1, but that isn't shown in your code. – ChrisMM Dec 05 '19 at 23:17
  • @ChrisMM I don't understand. The constructor is called once to create the first object and the copy constructor is called twice to clone the first object. It is shown by my example (with the addresses and the outputs) – ThunderPhoenix Dec 05 '19 at 23:19
  • 1
    there should be only 2 constructors call here. can you try on g++ compiler. – Abhishek Chandel Dec 05 '19 at 23:20
  • 1
    @ThunderPheonix, it should **not** be copying anything in the code you've given. See [here](https://godbolt.org/z/ZeGD4a) a more thorough example. – ChrisMM Dec 05 '19 at 23:21
  • With gcc 8.3.0 I get two calls to the constructor and two calls to the destructor. No copy constructor calls. – Willis Blackburn Dec 05 '19 at 23:24
  • @AbhishekChandel you are right. With `g++` there are two calls to constructor and two calls to destructor. I updated my question with the two outputs. – ThunderPhoenix Dec 05 '19 at 23:27
  • 1
    My guess is that the implementation of `std::vector` creates a "default" instance of the element type and then copies it into the new indexes created by the call to `resize`. I would just run it in the debugger and set a breakpoint inside the default constructor and copy constructors to see what's going on. – Willis Blackburn Dec 05 '19 at 23:28
  • @ChrisMM I agree with you. But windows c++ compiler doesn't work like that. – ThunderPhoenix Dec 05 '19 at 23:28
  • @ThunderPheonix It's probably the standard library you're using, not the compiler itself. You can look at the vector header file to see what it's doing. – Willis Blackburn Dec 05 '19 at 23:29
  • @ThunderPheonix can you check which version of g++ you are using on mingw32-g++.exe. – Abhishek Chandel Dec 05 '19 at 23:33
  • @AbhishekChandel How can I check the version of `g++` on `mingw32-g++.exe`? – ThunderPhoenix Dec 05 '19 at 23:39
  • @ThunderPheonix use `-v` to check version. BTW it might be illuminating to test both compilers with `-std=c++03` and `-std=c++11` each . – M.M Dec 05 '19 at 23:50

2 Answers2

0

Your compiler is doing some strange things for the code you've given, and I can only assume it is because you are using pre C++11. From cppreference, the resize method prior to C++11, took in a default constructed object as the second parameter if none was specified. This would cause the call to the constructor.

If the current size is less than count, additional elements are appended and initialized with copies of value.

This then means that the default constructed object would get copied into the two new spots which were allocated in the vector; which is what you are seeing with mingw

In C++11 and later, it should only call construct twice, and destructor twice, no copies involved. When t.resize(2) is called, two "Default Inserted" objects are added into the container, these would call the constructor. The destructors are called when the vector goes out of scope, and is destroyed.

If you do the following instead:

t.resize(2);
t.resize(5);

Now you will get some copies or moves on the second resize, if and only if the internal array is reallocated. The first two elements will be copied or moved from the old array to the new array. The last 3 elements will be Default Inserted into the new array.

As for the large difference in the memory addresses of the objects, this is really just how things work in computers. The initial array is allocated in one spot of dynamic memory; the resize then gets a new memory location, which may be right next to the old location, or may be entirely elsewhere.

Here is a demonstration with both C++17 and C++11.

ChrisMM
  • 8,448
  • 13
  • 29
  • 48
0

vector uses the constructor without parameters to a create a new object, and then, uses copy constructor to clone the previous object. Indeed, this code prove it:

Output of code does not prove anything, it only shows what one particular compiler did in one particular situation.

Prior to C++11 the standard specified that the new elements are created as if by insert copy-constructing from a value-initialized temporary. So the addresses differ because the objects in the vector are in dynamic storage, whereas the temporary is in temporary (or automatic) storage.

Since C++11 , it must create the new objects with default-insertion, which boils down to value-initialization for the default allocator.

Your results are most likely explained by using an old compiler (or not using C++11 mode on a more recent compiler).

M.M
  • 138,810
  • 21
  • 208
  • 365