将 std::string 添加到内存中具有 c-str 缓冲区值的 STL 容器的有效方法是什么?

What is the efficient way to add a std::string to a STL container with a value of a c-str buffer in memory?

假设我在内存中有一个字符缓冲区,其中包含一个 c_string,我想将一个 std::string 的对象与 c_string 的内容添加到一个标准容器,例如 std::list<std::string>,以一种高效的方式。

示例:

#include <list>
#include <string>

int main()
{
    std::list<std::string> list;

    char c_string_buffer[] {"For example"};

    list.push_back(c_string_buffer); // 1

    list.emplace_back(c_string_buffer); // 2

    list.push_back(std::move(std::string(c_string_buffer))); // 3
}

我使用 ReSharper C++,它抱怨 #1(并建议 #2)。

我读的时候push_back vs emplace_back, it says that when it is not an rvalue, the container will store a "copied" copy, not a moved copy. Meaning, #2 does the same as #1. Don’t blindly prefer emplace_back to push_back也谈到了。

案例 3:当我阅读 时,它说 std::move() 所做的“是对右值引用的强制转换,这可能会在某些情况下启用移动 ".

--

#3 实际上有任何好处吗?我假设 std::string 的构造函数被调用并创建了一个包含 c_string 内容的 std::string 对象。我不确定稍后容器是否构造另一个 std::string 并将第一个对象复制到第二个对象。

Does 3 actually give any benefit?

没有。 #1 已经在没有 std::move 的情况下移动了。 #3 只是写#1 的一种不必要的显式方式。

#2 通常 可能是最有效的。这就是为什么您的静态分析器会建议它。但是,正如文章所解释的那样,它在这种情况下并不重要,并且可能会受到 compile-time 的惩罚。我相信您可以通过使用 list.emplace_back(+c_string_buffer); 来避免潜在的 compile-time 成本,但这可能会让 reader.

感到困惑

// 3 完全等同于 // 1std::move 在这里什么都不做,因为 std::string(c_string_buffer) 已经是一个右值。

push_back 的问题与移动与复制无关。

如果您还没有元素类型的对象,

push_back 始终是一个糟糕的选择,因为它总是通过从元素类型的另一个对象复制或移动构造来创建新的容器元素。

如果你写 list.push_back(c_string_buffer); // 1,那么因为 push_back 需要一个 std::string&& 参数(或 const std::string&),一个 std::string 类型的临时对象将是从 c_string_buffer 和 passed-by-reference 到 push_back 构建。 push_back 然后从这个临时构造新元素。

使用 // 3 你只是在进行临时构造,否则会隐式显式地发生。

上面的第二步完全可以通过emplace_back来避免。它不是引用目标类型的对象,而是采用任意参数 by-reference,然后直接从参数构造新元素。不需要临时 std::string