当新容器的任何分配或元素的复制因异常而失败时,目标容器的当前内容是否会保持不变?
问问题
156 次
2 回答
3
我们在复制 C++ 容器时所拥有的异常安全保障是基本保障。
当你将容器 A 复制到容器 B 时,如果抛出异常,容器 B 将不会保持原样,其状态将被部分修改(部分覆盖)。
正如 Eljay 所说:复制过程中的异常将使原始容器处于定义良好的状态(假设它所持有的类型是行为良好的类型),并且复制到定义良好的容器中(尽管副本不完整)状态。
所有 C++ 标准库代码都提供(至少)基本保证。
我认为,原子性或强保证或防止创建部分对象不是标准规定的,因为强保证可能很昂贵。
您应该将源容器的内容复制到中间容器中,如果没有问题(没有抛出),则将中间容器的内容移动到目标容器中,否则,丢弃中间容器(或类似 copy- and-swap idiom),一个例子。
无论如何,您可以看到赋值运算符的实现。
我希望我至少能帮上一点忙,即使我是初学者。
编辑 :
class some_type final {
public:
constexpr some_type() noexcept : data(0) { }
explicit constexpr some_type(const int d) noexcept : data(d) { }
some_type(const some_type& other) : data(other.data) { error(); }
auto& operator=(const some_type& other) {
data = other.data;
error();
return *this;
}
constexpr auto get() const noexcept { return data; }
private:
static unsigned int copy_count;
int data;
void error() { if (++copy_count == 7) throw std::exception(); }
};
unsigned int some_type::copy_count = 0U;
示例 1:
int main()
{
std::vector src{ some_type(3), some_type(2), some_type(1), some_type(0)}; // +4 copies
std::vector<some_type> dest{ some_type(5) }; // +1 copy (5 copies)
std::cout <<
"\nDest Size : " << dest.size() << // size : 1
"\nDest Capacity : " << dest.capacity() << // capacity : 1
"\nDest Values : ";
for (const auto& value : dest)
std::cout << value.get() << ' '; // values : 5
try {
dest = src; // +4 copies (more than 7 copies, THROW!)
} catch (...) {
std::cout <<
"\n"
"\nDest Size : " << dest.size() << // size : 0
"\nDest Capacity : " << dest.capacity() << // capacity : 4
"\nDest Values : ";
for (const auto& value : dest)
std::cout << value.get() << ' '; // values :
std::cerr << "\n\nUnknown error : Something went wrong\n";
return 1;
}
}
示例 2:
int main()
{
std::vector src{ some_type(3), some_type(2), some_type(1), some_type(0)}; // +4 copies
std::vector<some_type> dest;
dest.reserve(4);
dest = { some_type(5) }; // +1 copy (5 copies)
std::cout <<
"\nDest Size : " << dest.size() << // size : 1
"\nDest Capacity : " << dest.capacity() << // capacity : 4
"\nDest Values : ";
for (const auto& value : dest)
std::cout << value.get() << ' '; // values : 5
try {
dest = src; // +4 copies (more than 7 copies, THROW!)
} catch (...) {
std::cout <<
"\n"
"\nDest Size : " << dest.size() << // size : 1
"\nDest Capacity : " << dest.capacity() << // capacity : 4
"\nDest Values : ";
for (const auto& value : dest)
std::cout << value.get() << ' '; // values : 3
std::cerr << "\n\nUnknown error : Something went wrong\n";
return 1;
}
}
如果您打印 dest 值,您将看到它被部分复制。
于 2021-12-20T17:10:35.367 回答
-6
我刚刚有了一个想法:我只是创建了一个向量并通过另一个向量对其进行了复制分配。在复制分配之前,第一个向量的大小大于第二个向量的大小。但是由于容量是原子实现之前的前一个大小,因此在这种情况下是不可能的。
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<size_t> toBeOverwritten;
toBeOverwritten.resize( 1000, 0 );
vector<size_t> overwriteFrom;
overwriteFrom.resize( 500, 0 );
toBeOverwritten = overwriteFrom;
cout << toBeOverwritten.capacity() << endl;
}
于 2021-12-20T16:01:35.810 回答