I want the following code to create 5 objects of the class "test" which call the constructor each time one is created,store them in a vector, print "lalalala" once, and then run the destructors and destroy the created objects. I want the destructor to run once for each object i created not more than once.
I think C++ in the following example is creating multiple extra copies of objects i do not want or else it calls the destructor way more times that it should. I am not sure. Tried gcc and clang no difference. Tried both with stack and heap allocation, as well as std::move. All produce the same results, way more destructor calls than i asked for.
Also i noticed some but not all C++ destructors are called before i print "lalala".
Why does this C++ code runs the destructor 17 times :
#include <iostream>
#include <vector>
using namespace std;
class test
{
public:
int t;
test(int i)
{
t = i;
cout << "Created instance " << t << ". \n";
}
~test()
{
cout << "(*)Deleted instance " << t << ".\n";
}
};
int main()
{
vector <test> V;
for(int i = 1; i <= 5; i++)
{
test D(i);
V.push_back(D);
}
cout << "LALALLALA \n";
return 0;
}
While this C# code does exactly what i want, 5 constructors and 5 destructors.
using System.IO;
using System;
using System.Collections.Generic;
class Program
{
class test
{
public int t;
public test(int i)
{
t = i;
Console.Write ("Created instance ");
Console.Write (t.ToString());
Console.WriteLine(".");
}
~test()
{
Console.Write( "(*)Deleted instance ");
Console.Write(t.ToString());
Console.WriteLine(".");
}
}
static void Main()
{
List<test> lst = new List<test>();
for(int i = 0; i < 5; i++)
{
test temp = new test(i);
lst.Add(temp);
}
Console.WriteLine("LALALLALA \n");
}
}
In C#, your List is storing references to objects. In C++, you are actually storing objects in the vector. Which means they need to be copied when they're put into the vector, and also when the vector needs to reallocate. Each one of those copies is a separate object (created with the copy constructor, which you're not tracking), and will have the destructor called on it.
A close approximation in C++ to what you are doing in C# would be to store pointers (or smart pointers) to heap allocated test objects, instead of test objects themselves
#include <memory> // for shared_ptr
int main()
{
std::vector<std::shared_ptr<test>> V;
for(int i = 1; i <= 5; i++)
{
auto D = std::make_shared<test>(i);
V.push_back(D);
}
std::cout << "LALALLALA \n";
return 0;
}
A preferred idiomatic C++ approach, if you want to be sure you just create 5 objects, but not have to allocate each one individually on the heap would be the following:
int main()
{
std::vector<test> V;
// ensure we can store 5 objects without reallocating
V.reserve(5);
for(int i = 1; i <= 5; i++)
{
// construct the object in place in the vector
V.emplace_back(i);
}
std::cout << "LALALLALA \n";
return 0;
}