【问题标题】:Can I emplace a value into a vector that is stored in a map in C++?我可以将一个值放入存储在 C++ 映射中的向量中吗?
【发布时间】:2020-05-01 23:21:41
【问题描述】:

我想知道是否可以将值放入存储在地图中的向量中。

目前我是这样做的......

std::map<std::string, std::vector<std::string>> my_collection;
my_collection["Key"].push_back("MyValue");

我在想我可以执行以下操作,并且 C++ 会足够聪明地意识到它应该将它添加到向量中......但我得到一个内存编译错误。

my_collection.emplace("Key", "MyValue");

【问题讨论】:

  • 您的第一个 sn-p 是这样做的唯一方法。没有什么魔法可以让编译器推断出你在想什么,它只能与你的代码一起工作——它应该用第二个 sn-p 做什么?用这个值替换所有矢量内容?插入它(在什么位置)?或者假设你犯了一个错误,因为类型不匹配?

标签: c++ emplace


【解决方案1】:

您可以创建一个向量,将其置入其中,然后移动该向量。这样您的对象就不会被复制或移动:

std::map<std::string, std::vector<std::string>> my_collection;
std::vector<std::string> temp;
temp.emplace_back("MyValue");
my_collection["Key"] = std::move(temp);

或者,您可以在地图中创建矢量并处理参考:

std::map<std::string, std::vector<std::string>> my_collection;
auto &keyVec = my_collection["Key"];
keyVec.emplace_back("MyValue");

方便地说,这归结为:

std::map<std::string, std::vector<std::string>> my_collection;
my_collection["Key"].emplace_back("MyValue");

【讨论】:

    【解决方案2】:

    无论 C++ 变得如何智能,它仍然必须尊重语言规则和公共接口。 std::map 确实有一个 emplace 成员。你需要使用它。

    问题是没有办法通过将元素移动到向量中来构造向量(因为 std::initializer_list 的设计方式 - 不要让我开始)

    如果您不关心这一点并且可以接受将元素复制到向量中,那么您需要做的就是:

    auto test()
    {
        using namespace std::string_literals;
    
        std::map<std::string, std::vector<std::string>> my_collection;
    
        my_collection.emplace("key"s, std::vector{"MyValue"s});
    }
    

    上面会将"MyValue"s复制到一个向量中,然后将键和向量移动到地图中。

    但是,如果您确实想要移动或只有移动类型,那么还有一些额外的工作。

    所以我创建了一个小实用函数:通过移动传递给它的右值来创建一个向量:

    template <class... Args>
    auto make_vector(Args&&... args)
    {
        using T = std::remove_reference_t<std::common_type_t<Args...>>;
        static_assert((... && std::is_same_v<T, std::remove_reference_t<Args>>));
    
        auto v = std::vector<T>{};
        v.reserve(sizeof...(Args));
        (..., v.emplace_back(std::forward<Args>(args))); 
    
        return v;
    }
    
    auto test()
    {
        using namespace std::string_literals;
    
        std::map<std::string, std::vector<std::string>> my_collection;
    
        my_collection.emplace("key", make_vector("MyValue"s));
    }
    

    【讨论】:

    • 但是这样“MyValue”不会被安顿。
    • @ypnos 你觉得怎么样?
    • 我可能错了,但我认为这个对象需要是可复制构造的,即使它可以被省略,不是吗?
    • @ypnos 好的,是时候进行一些研究了。
    • 根据我对标准的阅读,从初始化列表构造std::vector 的工作方式就像通过调用带有迭代器的构造函数一样。采用迭代器的构造函数从*i 中放置每个元素,其中i 是迭代器。 std::initializer_list&lt;T&gt; 的迭代器类型是 T const*。因此这里std::vector 的元素是由std::string const&amp; 构成的,它复制。
    猜你喜欢
    • 1970-01-01
    • 2017-06-03
    • 1970-01-01
    • 1970-01-01
    • 2011-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多