![](/img/trans.png)
[英]vector::push_back using std::move for internal reallocations
[英]std::vector reallocations in transactional way: copy and move constructors
在这个问题中,我想澄清有关 C++11 中的std::vector
重新分配的一些细节,并进一步说明。 我有一个包含所有已定义构造函数的 class Data
,并且我将这个 class 的对象放入std::vector
:
#include <iostream>
#include <vector>
struct Data
{
Data()
{
std::cout << "[Data]\n";
}
explicit Data(int v)
: ptr(new int(v))
{
std::cout << "[Data] v: " << v << "\n";
}
~Data()
{
if (ptr)
delete ptr;
std::cout << "[~Data]\n";
}
Data(const Data& rhs)
{
std::cout << "[Data] copy cntr\n";
*this = rhs;
}
Data& operator=(const Data& rhs)
{
if (this != &rhs)
{
if (rhs.ptr)
ptr = new int(*rhs.ptr);
}
return *this;
}
Data(Data&& rhs) noexcept
{
*this = std::move(rhs);
std::cout << "[Data] move cntr\n";
}
Data& operator=(Data&& rhs) noexcept
{
if (this != &rhs)
{
ptr = rhs.ptr;
rhs.ptr = nullptr;
}
return *this;
}
private:
int* ptr = nullptr;
};
int main()
{
std::vector<Data> values;
values.emplace_back(1);
values.emplace_back(2);
values.emplace_back(3);
values.emplace_back(4);
std::cout << "------\n";
return 0;
}
执行后我们有以下output:
[Data] v: 1
[Data] v: 2
[Data] move cntr
[~Data]
[Data] v: 3
[Data] move cntr
[Data] move cntr
[~Data]
[~Data]
[Data] v: 4
------
[~Data]
[~Data]
[~Data]
[~Data]
这里一切都很清楚。 在向量重新move_if_noexcept
期间,由于 move 构造函数是 noexcept,因此在底层调用 move_if_noexcept:
Data(Data&& rhs) noexcept
移动操作可以事务方式完成。 如果我删除 noexcept:
Data(Data&& rhs)
我将有以下output:
[Data] v: 1
[Data] v: 2
[Data] copy cntr
[~Data]
[Data] v: 3
[Data] copy cntr
[Data] copy cntr
[~Data]
[~Data]
[Data] v: 4
------
[~Data]
[~Data]
[~Data]
[~Data]
将调用复制构造函数(回退到复制)以保证可以事务完成的向量重新分配。 而那一刻,我真的不明白。 如果我明确删除复制构造函数和赋值:
Data(const Data& rhs) = delete;
Data& operator=(const Data& rhs) = delete;
尽管移动构造不是noexcept
,但 output 将如下所示:
[Data] v: 1
[Data] v: 2
[Data] move cntr
[~Data]
[Data] v: 3
[Data] move cntr
[Data] move cntr
[~Data]
[~Data]
[Data] v: 4
------
[~Data]
[~Data]
[~Data]
[~Data]
这是否意味着通过这种方式我们无法保证可以通过事务完成的重新分配(移动构造函数可以抛出异常并且向量将处于无效状态)? 可以吗? 我的期望是在这种情况下得到编译错误。
当复制构造函数不可用时, std::vector
除了使用移动构造函数之外别无选择,即使它可能会抛出。 在这种情况下,只能保证基本的异常安全(假设析构函数不能抛出)。
请注意,向量不会在无效的 state中,它将在有效的 state 中,但其内容可能与重新分配之前不同。 例如,它可能是空的,但仍然可用。
实际上,这种情况下的效果似乎是不确定的。 问题是,在这种情况下是否可以使用向量,以及是否保证元素被破坏。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.