2

在一些实现过程中,我遇到了关于异常安全保证和使用std::move(). 我知道 SO 不是问“你的意见是什么”(类模板Boo)这类问题的好地方,但在这里我想确定我的理解是否正确,在你阅读了这个问题之后,也许你可以指导我正确的道路。

考虑以下代码:

struct Foo {
    using Y = std::vector<std::string>;
    using X = std::vector<Y>;

    void add (Y y) {
        src.push_back (std::move (y));      // (1)
        src = process (std::move (src));    // (2)         
    }

private:
    X process (X&& vec) {                   // (F)
        for (auto& v : vec) {
            v.resize (10);                  // (3)
        }
        return std::move (vec);
    }


    X src;
};

看一下add()成员函数,如果从(1)中抛出异常并根据n4296 [vector.modifiers/1]

如果在末尾插入单个元素时抛出异常TisCopyInsertableis_nothrow_move_constructible<T>::valueis true,则没有效果。

那么强保证被保留了,对吗?

如果我们看(2)那么这里也可以抛出异常,因为(3)可以抛出异常。如果我错了,请纠正我:在这种情况下(2),如果我移动src到成员函数并且从那时process()抛出异常是未指定的,这意味着只保留基本保证?process()src

为了使add()成员函数得到强有力的保证,我应该将(2)和(F)分别更改为:

src = process (src); // (2)
X process (X vec);   // (F)

?

那么如果Foo::src元素数量巨大,那么做强保证会降低效率(因为必须制作额外的副本)?

也许保证级别应该由类的用户决定,通过使其成为类模板,类似于:

struct S {};
struct B {};

template <typename T>
struct Boo {
    using Y = std::vector<std::string>;
    using X = std::vector<Y>;

    void add (Y y) {
        src.push_back (std::move (y));
        src = process_helper (typename std::is_same<T, S>::type {});
    }


private:
    X process_helper (std::true_type) {
        return process (src);
    }

    X process_helper (std::false_type) {
        return process (std::move (src));
    }

    X process (X vec) {
        for (auto& v : vec) {
            v.resize (10);                  
        }
        return std::move (vec);
    }

    X src;
};

这是个好主意还是坏主意?

4

0 回答 0