【发布时间】:2020-09-05 00:20:39
【问题描述】:
考虑下面的代码,其中一些“MyType”类的对象存储在一个向量中,然后这个向量被传递给“VectorProcessor”类的一个对象:
// to compile, run: g++ -Wall --std=c++17 test.cpp -o test
#include <vector>
#include <iostream>
using namespace std;
class MyType {
private:
int x;
public:
MyType(int a_x) {
this->x = a_x;
cout << "MyType constructor; x=" << this->x << endl;
}
~MyType() {
cout << "MyType destructor; x=" << this->x << endl;
this->x = 0;
}
MyType(const MyType &o) {
this->x = o.x +10;
cout << "MyType copy constructor; x=x'+10=" << this->x << endl;
}
MyType& operator=(const MyType& o) {
this->x = o.x +20;
cout << "MyType =copy constructor; x=x'+20=" << this->x << endl;
return *this;
}
MyType(MyType &&o) {
this->x = o.x + 30;
cout << "MyType move constructor; x=x'+30=" << this->x << endl;
}
MyType & operator=(MyType &&o) {
this->x = o.x + 40;
cout << "MyType =move constructor; x=x'+40=" << this->x << endl;
return *this;
}
friend ostream& operator<<(ostream& os, const MyType& s) {
return os << s.x;
}
};
template <typename T>
class VectorProcessor {
private:
const vector<T> &v;
public:
VectorProcessor(const vector<T> &a_lista): v{a_lista} {
cout << "VectorProcessor constructor" << endl;
}
VectorProcessor(const vector<T> &&a_lista): v(a_lista) {
cout << "VectorProcessor rvalue constructor" << endl;
}
const T& getLast() {
return this->v[this->v.size()-1];
}
};
int main() {
#if 1
// test (A)
vector<MyType> v{1,2,3,4,5};
VectorProcessor<MyType> r(v);
#else
// test (B)
VectorProcessor<MyType> r(vector<MyType>{1,2,3,4,5});
#endif
cout << "r.getLast(): " << r.getLast() << endl;
return 0;
}
如果我启用“测试A”,程序输出是:
MyType constructor; x=1
MyType constructor; x=2
MyType constructor; x=3
MyType constructor; x=4
MyType constructor; x=5
MyType copy constructor; x=x'+10=11
MyType copy constructor; x=x'+10=12
MyType copy constructor; x=x'+10=13
MyType copy constructor; x=x'+10=14
MyType copy constructor; x=x'+10=15
MyType destructor; x=5
MyType destructor; x=4
MyType destructor; x=3
MyType destructor; x=2
MyType destructor; x=1
VectorProcessor constructor
r.getLast(): 15
MyType destructor; x=11
MyType destructor; x=12
MyType destructor; x=13
MyType destructor; x=14
MyType destructor; x=15
如果我启用“测试 B”,程序输出是:
MyType constructor; x=1
MyType constructor; x=2
MyType constructor; x=3
MyType constructor; x=4
MyType constructor; x=5
MyType copy constructor; x=x'+10=11
MyType copy constructor; x=x'+10=12
MyType copy constructor; x=x'+10=13
MyType copy constructor; x=x'+10=14
MyType copy constructor; x=x'+10=15
VectorProcessor rvalue constructor
MyType destructor; x=11
MyType destructor; x=12
MyType destructor; x=13
MyType destructor; x=14
MyType destructor; x=15
MyType destructor; x=5
MyType destructor; x=4
MyType destructor; x=3
MyType destructor; x=2
MyType destructor; x=1
r.getLast(): 0
然后我问:不使用指针,或者智能指针,
1) 如何避免在 MyType 类的对象中发生额外的复制(对于测试 A 和 B)?
2)在“测试B”中,为什么在r.getLast()之前调用了MyType析构函数?也就是说,如何将临时vector<MyType>{1,2,3,4,5}的生命周期延长到块的末尾?
【问题讨论】:
-
你写
=copy constructor的地方,实际上是复制赋值运算符(它不是构造函数)。与移动赋值运算符类似 -
来自更自以为是的 POV:如果不是您故意在各种构造函数中注入副作用,编译器很可能能够优化您调用移动构造函数所产生的任何成本额外的时间,所以区别可能并不像您期望的那么重要。
-
这个问题有点落后——一个更相关的问题通常是如何避免创建临时文件(或允许/强制编译器忽略它们)。一般来说,在语句中创建的未命名临时(例如,在您的情况 B 中,用于构造
r的对象)仅在语句结束之前存在。根据上下文,延长临时对象寿命的一种方法是给它一个名称(例如,初始化一个const引用以引用它)以便对象在引用在范围内时持续存在。但是一个未命名的临时对象的生命不能延长到封闭范围的末尾
标签: c++ c++11 constructor