下面是C ++中矢量回退方法的签名。
void push_back (const value_type& val);
现在下面是代码
class MyInt
{
int *a;
public:
MyInt(int n):a(new int(n)){cout<<"constructor called"<<endl;}
~MyInt(){cout<<"destructor called"<<endl;}
void show(){
cout<<*a<<endl;
}
};
void vector_test(vector<MyInt> &v)
{
MyInt m1(1);
MyInt m2(2);
v.push_back(m1);
v.push_back(m2);
}
Output
-------------
constructor called
constructor called
destructor called
destructor called
destructor called
1
2
destructor called
destructor called
在这里,我们看到在vector_test函数中创建的2个对象导致2次 构造函数调用。 但对于析构函数,它被调用了5次。
现在我的怀疑和疑问是
如果有人详细解释,我真的很感激。感谢..
答案 0 :(得分:1)
您还需要为复制构造函数添加日志记录:
MyInt(const MyInt& rhs):a(new int(*rhs.a)){cout<<"copy constructor called"<<endl;}
编译器允许一些构造函数调用被省略,即。在以下行中:
MyInt m1 = 1;
您可能希望首先调用复制构造函数来实例化临时MyInt(1)
,然后使用此临时调用复制构造函数。所以你会看到:
constructor called // for temporary
copy constructor called // for m1
destructor called // for m1
destructor called // for temporary
但由于copy elision编译器将使用m1
构造函数直接实例化您的MyInt(int n)
实例,即使您的复制构造函数有副作用(使用std :: cout)。因此,不会出现// for temporary
以上的日志。
要使用gcc,请使用-fno-elide-constructors
选项来复制构造函数elision。
同样优良的做法是使MyInt(int n)
这样的构造函数显式化,这是为了不允许错误地制作MyInt
对象实例 - 你必须明确它,即MyInt var; var = static_cast<MyInt>(1);
答案 1 :(得分:0)
您必须记住,如果您不提供这些方法,编译器可能会添加五种方法。在这种情况下,您受到编译器生成的复制构造函数的影响。
#include <iostream>
#include <vector>
using namespace std;
class MyInt
{
int *a;
public:
MyInt(int n):a(new int(n)){cout<<"constructor called"<<endl;}
MyInt(MyInt const& copy): a(new int(*copy.a)) {cout<<"copy constructor called"<<endl;}
MyInt(MyInt&& move): a(move.a) {move.a = nullptr; cout<<"move constructor called"<<endl;}
~MyInt(){cout<<"destructor called"<<endl;}
void show(){
cout<<*a<<endl;
}
};
void vector_test(vector<MyInt> &v)
{
MyInt m1(1);
MyInt m2(2);
v.push_back(m1);
v.push_back(m2);
}
int main()
{
vector<MyInt> v;
vector_test(v);
}
当我跑步时,我得到了
batman> ./a.out
constructor called
constructor called
copy constructor called
copy constructor called
copy constructor called
destructor called
destructor called
destructor called
destructor called
destructor called
注意:您正在从析构函数中泄漏内存。
这也是我们拥有emplace_back()
界面的原因。这将减少创建的对象的副本数。此外,当启用优化时,您将看到其中一些对象未被复制,而是就地创建。
void vector_test(vector<MyInt> &v)
{
MyInt m1(1);
MyInt m2(2);
// Can use emplace back
v.emplace_back(1); // Created the object in-place in the vector.
// Or you can use a temorary.
v.push_back(2); // Compiler sees there is a single argument constructor
// and will insert the constructor to convert a 2 into
// MyInt object.
v.push_back(MyInt(3)); // Or you can create a temporary explicitly.
}