-1

当新容器的任何分配或元素的复制因异常而失败时,目标容器的当前内容是否会保持不变?

4

2 回答 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 回答