C++標準是否保證插入關聯容器失敗不會修改rvalue-reference參數?




stl language-lawyer (2)

明確明確的 NO 。 Standard沒有這種保證,這就是為什麼 try_emplace 存在的原因。

請參閱註釋:

與insert或emplace不同, 如果不執行插入操作 這些函數就不會從rvalue參數中移出 ,這使得操作值僅為移動類型的 std::map<std::string, std::unique_ptr<foo>> (如 std::map<std::string, std::unique_ptr<foo>> 變得容易。 std::map<std::string, std::unique_ptr<foo>> 。 另外, try_emplace 對待 try_emplace 的鍵和參數,與emplace不同,emplace要求參數構造一個 value_type (即 std::pair )。

#include <set>
#include <string>
#include <cassert>

using namespace std::literals;

int main()
{
    auto coll = std::set{ "hello"s };
    auto s = "hello"s;
    coll.insert(std::move(s));
    assert("hello"s == s); // Always OK?
}

C ++標準是否保證插入關聯容器失敗不會修改rvalue-reference參數?


沒有。

雖然 @NathanOliver 指出,當且僅當沒有等效鍵時,才會插入元素,但這不能保證不會修改參數。

實際上,[map.modifiers]表示以下內容

template <class P>
pair<iterator, bool> insert(P&& x);

等效於 return emplace(std::forward<P>(x)).

其中 emplace 可以完美地轉發參數以構造另一個 P ,從而使 x 處於某些有效但不確定的狀態。

這是一個示例,該示例還演示(未證明)使用 std::map (關聯容器)時,值會稍微移動一下:

#include <iostream>
#include <utility>
#include <string>
#include <map>

struct my_class
{
    my_class() = default;
    my_class(my_class&& other)
    {
        std::cout << "move constructing my_class\n";
        val = other.val;
    }
    my_class(const my_class& other)
    {
        std::cout << "copy constructing my_class\n";
        val = other.val;
    }
    my_class& operator=(const my_class& other)
    {
        std::cout << "copy assigning my_class\n";
        val = other.val;
        return *this;
    }
    my_class& operator=(my_class& other)
    {
        std::cout << "move assigning my_class\n";
        val = other.val;
        return *this;
    }
    bool operator<(const my_class& other) const
    {
        return val < other.val;
    }
    int val = 0;
};

int main()
{
    std::map<my_class, int> my_map;
    my_class a;
    my_map[a] = 1;
    std::pair<my_class, int> b = std::make_pair(my_class{}, 2);
    my_map.insert(std::move(b)); // will print that the move ctor was called
}




pass-by-rvalue-reference