Here is my min ex:
#include <iostream>
#include <vector>
class A {
public:
A() { std::cout << "Constructor\n"; }
~A() { std::cout << "Destructor\n"; }
};
class B {
public:
B() { v.push_back(A()); v.push_back(A()); }
private:
std::vector<A> v;
};
int main() {
B b;
return 0;
}
So, I got this output:
Constructor // first push back
Destructor // copy destroyed
Constructor // second push back
Destructor // copy destroyed
Destructor // ???????????????
// B object goes out of scope and its vector too...
Destructor // v[0] destructor called
Destructor // v[1] destructor called
Can someone shed some light please?
After following Dave's comment:
Constructor
Copy constructor
Destructor
Constructor
Copy constructor
Copy constructor
Destructor
Destructor
Destructor
Destructor
Adding in an overloaded copy constructor and some indicator of which object is being acted upon sheds some light on the situation:
#include <iostream>
#include <vector>
class A {
public:
A(unsigned i): i(i) { std::cout << "Constructor " << i << std::endl; }
A(const A& a) : i(a.i) { std::cout << "Copy constructor " << i << std::endl; }
~A() { std::cout << "Destructor " << i << std::endl; }
unsigned i;
};
class B {
public:
B() { v.push_back(A(0)); v.push_back(A(1)); }
private:
std::vector<A> v;
};
int main() {
B b;
return 0;
}
On the first push, we make a copy and destroy the temporary. On the second push, we make a copy, then copy the first object, before destroying the first object and the temporary. Finally, we destroy both objects.
I'd guess that the std::vector was first allocated with a capacity of 1, so the second push forced a re-allocation? If I force a larger initial capacity (by calling v.reserve(5) before the first push), then the extra copy disappears.
You are not tracking construction of As using the default copy constructor. If you add a copy constructor and a message in it, the number of calls to constructors should match the number of calls to the destructor.
Modifying declaration of class A as follows,
class A
{
public:
A() { std::cout << "Constructor " << this << std::endl; }
A(const A&) { std::cout << "Copy Constructor " << this << std::endl; }
~A() { std::cout << "Destructor " << this << std::endl; }
};
running the program at http://coliru.stacked-crooked.com/
gives output:
Constructor 0x7fffecb8dc0f
Copy Constructor 0x1efdc20
Destructor 0x7fffecb8dc0f
Constructor 0x7fffecb8dc0e
Copy Constructor 0x1efdc41
Copy Constructor 0x1efdc40
Destructor 0x1efdc20
Destructor 0x7fffecb8dc0e
Destructor 0x1efdc40
Destructor 0x1efdc41
which clearly shows the construction and destruction of objects , both on stack and on heap (0x1efdc20, 0x1efdc40, and 0x1efdc41 are locations of the objects allocated by the vector).
Related
I have this simple class with two specialized constructors.
#include <iostream>
class test_01
{
std::string name;
uint16_t value;
public:
test_01(std::string name);
test_01(uint16_t value);
~test_01();
void show_message(std::string message);
};
test_01::test_01(std::string name)
{
std::cout << "Constructor string is called" << std::endl;
test_01::name = name;
}
test_01::test_01(uint16_t value)
{
std::cout << "Constructor uint16 is called" << std::endl;
test_01::value = value;
}
test_01::~test_01()
{
std::cout << "Destructor is called" << std::endl;
}
void test_01::show_message(std::string message)
{
std::cout << message.c_str() << std::endl;
}
int main()
{
bool result = true;
test_01 t = result ? test_01("test") : test_01(57);
t.show_message("hello");
}
Each constructor is called depending on an external condition. When the ternary operator is executed a destructor is called. Thus.
Constructor string is called
Destructor is called
hello
Destructor is called
I don't understand why the first destructor is called
Thanks !
Because there are two test_01 objects created, so two must be destroyed.
first is exactly one of
vvvvvvvvvvvvvvv or vvvvvvvvvvvv
test_01 t = result ? test_01("test") : test_01(57);
^ second is here
Had you added logging to the copy or move constructors, you would see, a temporary object is copied/moved into t object, which is move/copy constructed from this temporary.
I used to assume that a class' move constructors would be given priority over its copy constructors, but in the code below it seems that the copy constructor is chosen even though the object should be movable.
Do you have any idea why below codes choose copy constructor when foo() returns vector<B> B?
#include <iostream>
#include <vector>
using namespace std;
class B {
public:
int var_;
B(int var) : var_(var)
{
cout << "I'm normal" << endl;
}
B(const B& other)
{
cout << "I'm copy constructor" << endl;
}
B(B&& other)
{
cout << "I'm move constructor" << endl;
}
};
vector<B> foo()
{
vector<B> b;
b.push_back(1);
b.push_back(2);
return b;
}
int main()
{
vector<B> b {foo()};
}
The result is as shown below.
$ g++ main.cpp
$ a.out
I'm normal
I'm move constructor
I'm normal
I'm move constructor
I'm copy constructor
Curiously, if I remove one line in foo(), the move constructor is chosen instead:
vector<B> foo()
{
vector<B> b;
b.push_back(1);
return b;
}
Now the result is like below:
$ g++ main.cpp
$ a.out
I'm normal
I'm move constructor
There are two things involved: vector reallocation and selection of mechanism when reallocating.
First, reallocation occurs here:
vector<B> foo()
{
vector<B> b;
b.push_back(1);
std::cout << "Vector capacity: " << b.capacity() << " Vector size: " << b.size() << "\n";
b.push_back(2); //capacity() == size(), reallocation is needed
return b;
}
Most vector implementations make capacity 2*current_capacity when current_capacity would be exceeded, to conform to amortized-constant complexity required by standard.
Now, compiler can only choose move constructor for reallocation if it is marked as noexcept. In order to make vector use move constructor, declare it like this:
B(B&& other) noexcept
{
//
}
You can remove the reallocation altogether by reserving space upfront:
vector<B> foo()
{
vector<B> b;
b.reserve(2);
b.push_back(1);
b.push_back(2);
return b;
}
Or by initializing vector in one go:
vector<B> foo()
{
return vector<B>{1, 2};
}
lets say I have a class with 2 constructors like so:
class Foo
{
Foo(int x);
Foo();
...
}
I know that I can call one constructor from another like Foo() : Foo(42) {}, but why shouldn't (or should) I do the following:
Foo() {
Foo(42)
}
What is the difference in these cases?
Some suggest to use an "initializer" method, called from any constructor with their respective arguments, but I am puzzled as to what happens in the case above?
Let's put this example:
#include <iostream>
class B
{
private:
int number;
public:
B()
{
B(1);
}
B(int x) : number(x)
{
std::cout << "Constructor: " << x << std::endl;
}
void print(){
std::cout << "Msg: " << number << std::endl;
}
~B(){std::cout << "Destructor: " << number << std::endl;}
};
int main() {
B b;
b.print();
return 0;
}
Output:
Constructor: 1
Destructor: 1
Msg: 1
Destructor: 1
You are destroying a second object! This is strange, what happens if we use pointers...
#include <iostream>
class B
{
private:
int* arr;
public:
B()
{
B(1);
}
B(int x)
{
std::cout << "Constructor: " << x << std::endl;
arr = new int[x];
}
void print(int n){
std::cout << "Msg: " << arr[n] << std::endl;
}
void set(int n,int val){
arr[n] = val;
}
~B()
{
std::cout << "Destructor: " << arr << std::endl;
delete[] arr;
}
};
int main() {
B b;
b.set(0,14);
b.print(0);
return 0;
}
Constructor: 1
Destructor: 0xc45480
Msg: 14
Destructor: 0xc45480
Look up the pointer addr. They are the same, this means:
We are writing in deleted memory.
We are deleting the same memory twice.
These are two serious problems. You shouldn't do that.
Expression Foo(){Foo(42);} constructs anonymous temporary object that gets destroyed immediately without changing the object being constructed anyhow, while from Foo() : Foo(42){} will initialize the object being constructed.
You should not the following:
Foo() {
Foo(42)
}
When you are in the constructor body the member variables have been just constructed. That's why in C++ initialisation list exists.
The above code is semantically wrong! You are not absolutely using
delegating construction. Instead the statement Foo(42) in the body will just create another object without assigning it to any variable (anonymous variable).
You can imagine something like:
Foo() {
Foo another_obj = Foo(42);
}
In order to use delegating constructor, you must call constructor
in the initialisation list.
Foo() : Foo(42) { }
I created a basic test class to learn how the move constructor works. The move constructor does not seem to be called, and I'm not sure what constructor is actually called. If I use std::move then the move constructor is called, but a regular R value won't actually call it. Why is this happening, and what constructor is actually being called? I'm using g++ 4.6.3
#include <iostream>
#include <cstring>
class Test
{
int a;
int b;
int* c;
public:
Test(int one, int two)
{
std::cout << "Param Constructor" << "\n";
a = one;
b = two;
}
Test()
{
std::cout << "Default Constructor" << "\n";
a = 1;
b = 2;
}
~Test()
{
std::cout << "Deconstructor" << "\n";
}
Test(const Test& test)
{
a = test.a;
b = test.b;
std::cout << "Copy constructor called" << "\n";
}
Test(Test&& test)
{
std::cout << "Move constructor called" << "\n";
a = test.a;
b = test.b;
}
Test& operator=(const Test& test)
{
std::cout << "in operator=" << "\n";
a = test.a;
b = test.b;
return *this;
}
};
Test createTest()
{
return Test(1,2);
}
int main()
{
Test test(createTest());
Test test2 = test;
std::cout << "After logic" << "\n";
return 0;
}
The output I get:
Param Constructor
Copy constructor called
After logic
Deconstructor
Deconstructor
I create an object of type Test with the name test, but there is no output of it being created? I was expecting this output:
Param Constructor
Move Constructor // (Missing)
Deconstructor //Deleting instance from createTest (Missing)
Copy constructor called
After logic
Deconstructor
Deconstructor
what constructor is actually being called?
No constructor at all. Count the number of destructor calls. You'll find that there is one less than you expected. The temporary that you expected to be constructed wasn't created at all.
Why is this happening
The compiler avoided creation of the temporary. Instead, the object was constructed in place where it would have been moved to otherwise. This is known as copy elision.
If I modify the assignment opreator so that it returns an object A instead of a reference to an object A then something funny happens.
Whenever the assignment operator is called, the copy constructor is called right afterwards. Why is this?
#include <iostream>
using namespace std;
class A {
private:
static int id;
int token;
public:
A() { token = id++; cout << token << " ctor called\n";}
A(const A& a) {token = id++; cout << token << " copy ctor called\n"; }
A /*&*/operator=(const A &rhs) { cout << token << " assignment operator called\n"; return *this; }
};
int A::id = 0;
A test() {
return A();
}
int main() {
A a;
cout << "STARTING\n";
A b = a;
cout << "TEST\n";
b = a;
cout << "START c";
A *c = new A(a);
cout << "END\n";
b = a;
cout << "ALMOST ENDING\n";
A d(a);
cout << "FINAL\n";
A e = A();
cout << "test()";
test();
delete c;
return 0;
}
The output is as follows:
0 ctor called
STARTING
1 copy ctor called
TEST
1 assignment operator called
2 copy ctor called
START c3 copy ctor called
END
1 assignment operator called
4 copy ctor called
ALMOST ENDING
5 copy ctor called
FINAL
6 ctor called
test()7 ctor called
Because if you don't return a reference of the object it makes a copy.
As #M.M said about the final test() call, the copy does not appears because of the copy elision What are copy elision and return value optimization?