是否为数组/向量插入调用了赋值运算符或复制构造函数?
Posted
技术标签:
【中文标题】是否为数组/向量插入调用了赋值运算符或复制构造函数?【英文标题】:Is Assignment Operator or Copy Constructor invoked for array/vector insertions? 【发布时间】:2018-10-24 19:04:53 【问题描述】:语言:C++
我的问题是在以下情况下是否调用了复制构造函数或赋值运算符。在此之前,我理解以下内容:
MyClass a(3); // single param constructor
MyClass b(a); // copy constructor invoked
MyClass c = b; // copy constructor invoked
MyClass d; // default constructor
d = c; // assignment operator invoked
但是,我希望有人可以为这些提供类似的细分:
1) 对于第 2-3 行,是否调用了赋值运算符或复制构造函数?
MyClass arr[10];
arr[2] = a;
arr[5] = MyClass(1);
2) 构造函数,然后是复制构造函数?还是构造函数,然后是赋值运算符?
MyClass arr2[] = MyClass(), MyClass(9);
3) 假设向量v
的内部表示有空间容纳另一个对象,是使用赋值运算符还是复制构造函数复制新元素?
std::vector<MyClass> v;
v.push_back(MyClass(2));
...
...
4) 假设向量v
的内部表示空间不足且必须重新分配,是使用赋值运算符还是复制构造函数复制旧元素?
v.push_back(MyClass(2)); // Assuming vector is out of space; must realloc
【问题讨论】:
1) 通过在相关功能中打印诊断方法,您能找到自己吗? 2)这些答案是具体实现的吗? 1) 你完全错过了移动构建。 2)std::vector
如何调整大小取决于移动构造函数是否不抛出。
构造函数用于构造。赋值运算符用于修改已经构造好的对象
【参考方案1】:
MyClass arr[10];
MyClass 的构造函数被调用了 10 次,因为创建了 10 个 arr 对象。
arr[2] = a;
调用赋值运算符,将arr[2]
赋值给a
。
arr[5] = MyClass(1);
第一个带有参数1
的单参数构造函数被调用并创建了一个MyClass 的对象。然后调用赋值运算符。
MyClass arr2[] = MyClass(), MyClass(9);
这里只调用了两个构造函数。首先是Myclass()
,然后是“单参数构造函数”MyClass(9)
。带有初始化的数组声明不是赋值,因为不存在可以赋值的现有数组成员。
std::vector<MyClass> v;
std::vector<MyClass>
的构造函数被调用。
v.push_back(MyClass(2));
std::vector::push_back
创建类的副本并存储它。所以首先调用MyClass(2)
构造函数,然后调用复制构造函数MyClass(const MyClass &)
来复制值。然后存储复制的对象。
假设向量 v 的内部表示空间不足并且必须重新分配,是使用赋值运算符还是复制构造函数复制旧元素?
为每个成员调用复制运算符。所以:
std::vector<MyClass> a;
为std::vector<MyClass>
调用构造函数
a.push_back(MyClass(1));
调用MyClass(1)
的构造函数并使用复制构造函数MyClass(MyClass&)
复制它。
之后,如果我们向数组中添加另一个元素:
a.push_back(MyClass(2));
然后调用MyClass(2)
构造函数,然后为刚刚构造的MyClass(2)
对象调用MyClass(MyClass&)
的复制构造函数。然后向量复制构造来自 ned 的所有现有成员,因此对于向量MyClass(1)
中的预先存在的对象,调用已经向上的复制构造函数。
真的,玩一下。并在任何地方插入 cout 以查看它:
struct MyClass
MyClass(int a = 0) : _a(a)
_count = count++;
std::cout << __func__ << " "
<< _count << " "
<< this << " "
<< this->_a << "\n";
MyClass(const MyClass &old_obj)
this->_a = old_obj._a;
std::cout << __func__ << "Copy "
<< _count << " "
<< this << " "
<< this->_a << " "
<< &old_obj << " "
<< old_obj._a << "\n";
void operator=(const MyClass &old_obj)
this->_a = old_obj._a;
std::cout << "MyClass" << __func__ << " "
<< _count << " "
<< this << " "
<< this->_a << " "
<< &old_obj << " "
<< old_obj._a << "\n";
static int count;
int _count;
int _a;
;
int MyClass::count = 0;
【讨论】:
【参考方案2】:当你有
type variable_name = some_value
那么你声明了一个变量并且总是调用它的构造函数(如果有的话)。这称为复制初始化,永远不会被赋值
所以,在
MyClass arr[10]; // 1
arr[2] = a; // 2
arr[5] = MyClass(1); // 3
第 1 行创建一个包含 10 个 MyClass
的数组,并默认构造每个数组。第 2 行和第 3 行是赋值。
在
MyClass arr2[] = MyClass(), MyClass(9);
您使用 *braced-init-list` 中的值作为数组成员的初始化器来初始化 2 个对象的数组。管理list initialization 的规则有很多,但它们的共同点是不会发生赋值,只会发生构造函数调用。
有
std::vector<MyClass> v;
v.push_back(MyClass(2));
假设向量没有重新分配,您有一个构造函数调用MyClass(2)
,然后向量中的元素是从该临时对象复制构造的。如果向量必须增长,则将所有当前元素复制/移动构造到新缓冲区,然后在最后复制临时元素。
【讨论】:
以上是关于是否为数组/向量插入调用了赋值运算符或复制构造函数?的主要内容,如果未能解决你的问题,请参考以下文章