C++矢量推回方法和临时对象创建
C++ vector pushback method and temporary object creation
下面是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次。
现在我的疑虑和问题是
- 为什么构造函数和析构函数调用的数量不匹配
- 我知道有一些临时对象正在创建中。但这种机制是如何运作的呢
- 只是为了测试,我试图提供一个复制构造函数,但它导致编译失败。原因可能是什么
- 是否有一些逻辑将m1和m2的内容复制到新对象中并放入容器中
如果有人能详细解释一下,我将不胜感激。谢谢
您还需要为复制构造函数添加日志记录
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
但是由于复制省略,编译器将使用MyInt(int n)
构造函数直接实例化您的m1
实例,即使您的复制构造函数有副作用(使用std::cout)。因此不会出现上述// for temporary
日志。
要在gcc中看到这一点,请使用:-fno-elide-constructors
选项,该选项将复制构造函数省略。
同样,让MyInt(int n)
这样的构造函数显式也是一种很好的做法,这是为了不允许错误地创建MyInt
对象实例——你必须让它显式,即MyInt var; var = static_cast<MyInt>(1);
。
您必须记住,如果不提供五个方法,编译器可能会添加它们。在这种情况下,您会受到编译器生成的副本构造函数的影响。
#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.
}
相关文章:
- 为什么当我们有常量引用时创建临时对象?
- 为什么在按值返回时创建临时对象,而不是在按值传递给函数参数时创建临时对象
- 我试图创建临时对象的方式有错误吗
- 将项添加到矢量而不创建临时对象
- 在此初始化中创建的临时对象数
- 在没有返回值优化的情况下将两个对象加在一起时,将创建多少个临时对象
- C++:如何创建一个临时对象,包含一个指针 - 常量或非常量,具体取决于上下文
- 按值函数创建范围的临时对象
- 从函数返回引用是否会导致在使用'auto'时创建新的临时对象?
- C++17:是编译器为(静态存储持续时间)const引用绑定创建的可修改的临时对象(和存储)
- 临时对象创建
- 我如何知道何时创建和销毁临时对象
- C++矢量推回方法和临时对象创建
- 当我从内联函数返回字符串时,会创建多少个临时对象
- 我应该创建一个临时对象来实例化C++中的成员变量吗
- Visual Studio 在类型转换时不会创建临时对象
- 如何避免在使用初始值设定项列表构造时创建(和删除)临时对象
- 通过引用捕获异常时未创建临时对象
- 临时对象 - 何时创建它们,如何在代码中识别它们
- 何时调用使用"new"创建的临时对象'delete'?