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.
Related
Let's consider this simple code
#include <iostream>
#include <map>
class my_class {
std::string name;
int age;
public:
my_class():name(""), age(0) {
std::cout << "Default constructor" << std::endl;
}
my_class(std::string nm, int a) : name(nm), age(a) {
std::cout << "Constructor with both parameters" << std::endl;
}
my_class(const my_class& obj) {
std::cout << "copy_constructor " << std::endl;
name = obj.name;
age = obj.age;
}
void show() {
std::cout << "name=: " << name << "age=: " << age <<std::endl;
}
};
int main() {
std::map<int, my_class> m;
m[0];
return 0;
}
I compile it via this gcc (version of my gcc: gcc version 5.4.0 20160609):
g++ -o main main.cpp
After run we see that copy constructor has been called two times:
Default constructor
copy_constructor
copy_constructor
First call of copy constructor it is because of operator[]. A call to this function is equivalent to:
(*((this->insert(make_pair(k,mapped_type()))).first)).second
So we see that make_pair calls copy constructor of my_class.
But the reason of the second call of copy constructor is not clear for me. I'm only supposing that it creates a temporary object into make_pair implementation. Am I correct ?
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.
I am studying constructor, copy constructors and copy assignment a while and I read a fair amount of contents mainly from here as In which situations is the C++ copy constructor called? and What is The Rule of Three? and others, but I still no deeply understanding their exactly behavior. I am performing some tests with the class Boo and Foo bellow and their results are not the ones that I was expecting. In the class Boo I explictly declared its default constructor, copy constructor and copy assingment, and I defined them to do nothing. From this I was expecting that the objects from this class would have member variables with random values, what was indeed observed. Nevertheless, this behavior was not seen with the objects from the class Foo. The only difference between these classes are that the later is a singleton, but its default constructor, copy constructor and copy assignment still explicit declared and defined to do nothing. From this I state my question: Why the values of the member variables of objects from class Foo are not randomly initialized, but always has de same value of "0" and " "?
#include <iostream>
class Boo {
private:
int x;
char y;
public:
int getInt() { return x; }
char getChar() { return y; }
Boo () { std::cout << "Boo default constructor\n"; }
Boo ( const Boo& other ) { std::cout << "Boo copy constructor\n"; }
Boo& operator= ( const Boo& other) { std::cout << "Boo copy assinment\n";
return *this;}
};
class Foo {
private:
int x;
char y;
static Foo *instance;
protected:
Foo() { std::cout << "Foo default constructor\n"; }
Foo ( const Foo& other ) { std::cout << "Foo copy constructor\n"; }
Foo& operator=( const Foo& other) { std::cout << "Foo copy assignment\n"; }
public:
static Foo & uniqueInst();
int getInt() { return x; }
char getChar() { return y; }
};
Foo *Foo::instance = 0;
Foo & Foo::uniqueInst(){
if(!instance) instance = new Foo();
return *instance;
};
int main(){
Boo b1; // default constructor
Boo b2; // default constructor
Boo b3 = b1; // copy constructor
b2 = b1;
std::cout << b1.getInt() << std::endl; // Random values since the constructor does nothing
std::cout << b1.getChar() << std::endl;
std::cout << b2.getInt() << std::endl; // Random values since the copy assignment does nothing
std::cout << b2.getChar() << std::endl;
std::cout << b3.getInt() << std::endl; // Random values since the copy constructor does nothing
std::cout << b3.getChar() << std::endl;
Foo *foo;
foo = &Foo::uniqueInst(); // defaulf construtor
std::cout << foo << std::endl;
std::cout << foo->getInt() << std::endl; // Why not random values?
std::cout << foo->getChar() << std::endl;
};
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?
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).