[英]C++ vector pushback method and temporary object creation
Below is the signature of vector pushback method in C++. 下面是C ++中向量推回方法的签名。
void push_back (const value_type& val);
Now below is code 现在下面是代码
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
Here we see that for 2 objects which is created in vector_test function causes 2 times constructor invocation. 在这里,我们看到在vector_test函数中创建的2个对象导致2次构造函数调用。 But for destructor it got invoked 5 times.
但是对于析构函数,它被调用了5次。
Now my doubts and questions are 现在我的疑问和疑问是
I would really appreciate if someone explain this in detail. 如果有人详细解释,我将不胜感激。 Thanks..
谢谢..
You need to add logging also for copy constructor: 您还需要为复制构造函数添加日志记录:
MyInt(const MyInt& rhs):a(new int(*rhs.a)){cout<<"copy constructor called"<<endl;}
Some constructor calls are allowed by compiler to be elided, ie. 编译器允许省略一些构造函数调用,即。 in following line:
在以下行中:
MyInt m1 = 1;
you might expect copy constructor to be first called to instantiate temporary MyInt(1)
then a copy constructor called with this temporary. 您可能希望首先调用复制构造函数以实例化临时
MyInt(1)
然后再调用一个与此临时复制实例一起调用的复制构造函数。 So you would see: 这样您会看到:
constructor called // for temporary
copy constructor called // for m1
destructor called // for m1
destructor called // for temporary
but because of copy elision compiler will directly instantiate your m1
instance using MyInt(int n)
constructor, even though your copy constructor has side effects (std::cout is used). 但是由于复制省略,编译器将使用
MyInt(int n)
构造函数直接实例化您的m1
实例,即使您的复制构造函数具有副作用(使用std :: cout)。 So no above // for temporary
logs will be present. 因此将不存在
// for temporary
以上// for temporary
日志。
To see this with gcc use: -fno-elide-constructors
option which diasbles copy constructor elision. 要在gcc中使用以下命令,请使用:
-fno-elide-constructors
elide -fno-elide-constructors
选项,该选项可避免复制构造函数省略。
Also it is a good practice to make constructors such as MyInt(int n)
explicit, this is to disallow making MyInt
object instance by mistake - you will have to make it explicit, ie MyInt var; var = static_cast<MyInt>(1);
将诸如
MyInt(int n)
构造函数设为显式也是一个好习惯,这是不允许错误地使MyInt
对象实例成为MyInt
-您必须将其显式化,即MyInt var; var = static_cast<MyInt>(1);
MyInt var; var = static_cast<MyInt>(1);
. 。
You have to remember that the compiler can potentially add five methods if you don't provide them. 您必须记住,如果不提供编译器,则可能会添加五个方法。 Im this case you are being affected by the compiler generated copy constructor.
在这种情况下,您会受到编译器生成的副本构造函数的影响。
#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);
}
When I run this I get 当我运行这个我得到
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
Note: You are leaking memory from the destructor. 注意:您正在从析构函数中泄漏内存。
This is also why we have the emplace_back()
interface. 这也是为什么我们有
emplace_back()
接口的原因。 This will reduce the number of copies of the object that are created. 这将减少所创建对象的副本数。 Additionally when optimizations are enabled you will see that some of those object are not copied but created in-place.
此外,启用优化后,您会看到其中的某些对象未复制,而是就地创建。
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.
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.