Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filling std::vector with objects created elsewhere

I'm trying to fill a std::vector with objects created in a function like so:

class Foo
{
public:
   Foo() { std::cout << "Foo created!\n"; }
   Foo(const Foo& other) { std::cout << "Foo copied!\n"; }
   Foo(Foo&& other) { std::cout << "Foo moved\n"; }
   ~Foo() { std::cout << "Foo destroyed\n"; }
};

static Foo createFoo() 
{
   return Foo();
}

int main()
{
   {
       std::vector<Foo> fooVector;
       fooVector.reserve(2);
       fooVector.push_back(createFoo());
       fooVector.push_back(createFoo());
       std::cout << "reaching end of scope\n";
   }
   std::cin.get();
}

Output:

Foo created!
Foo moved
Foo destroyed
Foo created!
Foo moved
Foo destroyed
reaching end of scope
Foo destroyed
Foo destroyed

How can Foo be destroyed more times than it is created? I don't understand what is happening here, I thought that Foo would be copied, but the copy constructor is not triggered.

What is the best way to fill a std::vector with objects created elsewhere without them being destroyed?

like image 987
MrEighteen Avatar asked Jun 10 '20 15:06

MrEighteen


People also ask

How do you add an object to a vector?

boolean add(Object element): This method appends the specified element to the end of this vector. Parameters: This function accepts a single parameter element as shown in the above syntax. The element specified by this parameter is appended to end of the vector.

What is the main issue with storing objects in the vector class as opposed to pointers?

Having vector of objects is much slower than a vector of pointers. The results are because algorithms such as sorting need to move elements inside the container. So they not only read the data but also perform a copy (when the algorithm decides to swap items or move to a correct place according to the order).

Are vectors automatically deallocated C++?

Arrays have to be deallocated explicitly if defined dynamically whereas vectors are automatically de-allocated from heap memory.

Can we add an element in the middle in vector?

Elements can be added in the middle of a Vector by using the java. util. Vector. insertElementAt() method.


3 Answers

How can Foo be destroyed more times than it is created?

The output shows exactly as many creations, as it shows destructions:

            change -> cumulative total    
Foo created!    +1 -> 1
Foo moved       +1 -> 2
Foo destroyed   -1 -> 1
Foo created!    +1 -> 2
Foo moved       +1 -> 3
Foo destroyed   -1 -> 2
reaching end of scope
Foo destroyed   -1 -> 1
Foo destroyed   -1 -> 0 all objects that were created are now destroyed

I thought that Foo would be copied, but the copy constructor is not triggered.

Each time you pass an rvalue to the constructor. That is why the move constructor is used instead of copy constructor.


What is the best way to fill a std::vector with objects created elsewhere without them being destroyed?

Well, by not destroying the objects that you created elsewhere... But usually you should avoid doing that, since it is typically a memory leak.

If you create two objects elsewhere and two objects in a vector, then you end up with having created 4 objects. If you wanted only two objects, then for example create the objects directly into the vector and nowhere else. Like this for example:

fooVector.emplace_back();
fooVector.emplace_back();
like image 177
eerorika Avatar answered Nov 09 '22 19:11

eerorika


When you do

fooVector.push_back(createFoo());

First createFoo() creates a temporary Foo object, this is why you see

Foo created!

Then, that object is "moved" into the vector since it is a prvalue. This is why you see

Foo moved

Now you have an object in the vector, but you also have that temporay object that was created, moving doesn't get rid of that object, it just moves its internals into the object in the vector. You still need to destroy that object once it goes out of scoped and that happens at the end of the full expression giving you the

Foo destroyed

output.

like image 44
NathanOliver Avatar answered Nov 09 '22 19:11

NathanOliver


When you make std::move(obj), the state of the moved object is supposed to be a new state which can be destroyed. This happens usually by transferring the data held by the object to a new object (will be constructed using move ctor). and finally the object we have taken its content will be destroyed too.

Now each move operation will construct a new object and leave the old one in a state to be destroyed, hence you have the right output 4 constructions (2 by default ctor and two by move ctor) and the corresponding 4 destructions.

like image 29
asmmo Avatar answered Nov 09 '22 20:11

asmmo