在构造函数中初始化字符串成员的首选方法是什么?

时间:2018-08-08 13:53:03

标签: c++ c++17

下面是一个具有一个字符串成员的类。我们想在构造函数中对其进行初始化:

class MyStr {
    std::string m_str;

public:
    MyStr(const std::string& rstr) : m_str(rstr) {}
};

构造函数采用const std :: string&。

我们可以将常量引用替换为string_view:

MyStr(std::string_view strv) : m_str(strv) {}

或按值传递字符串并从中移出:

MyStr(std::string str) : m_str(std::move(str)) {}

首选哪一种?

3例:

MyStr mystro1{"Case 1: From a string literal"};

std::string str2 { "Case 2: From l-value"};
MyStr mystro2 { str2 };

std::string str3 { "Case 3: From r-value reference"};
MyStr mystro3 { std::move(str3) };

4 个答案:

答案 0 :(得分:2)

最有效的方法是完善转发可转换为std::string的任何参数:

class MyStr {
    std::string m_str;

public:
    template<class T,
             class = std::enable_if_t<std::is_convertible<std::remove_reference_t<T>, std::string>::value>>
    MyStr(T&& arg)
        : m_str(std::forward<T>(arg))
    {}
};

虽然有点大嘴。第二个最佳选择是根本不提供构造函数,不公开数据成员,并使用聚合初始化语法初始化MyStr

完整的故事:CppCon 2017: Nicolai Josuttis “The Nightmare of Move Semantics for Trivial Classes”

答案 1 :(得分:1)

这是实践经验法则,适用范围更广:

  

按值传递所有廉价移动 接收参数,并在适当时使用std::move

     

主要示例是不可 廉价移动的类型:std::array和其他类型{{1} },其中T是“大”

这通常是可用性(在接口的任一侧)和计算开销之间的良好折衷。通常,额外的工作(相对于完美的转发)最多是一个额外的移动构造,最多是一个额外的解构。除非您确定了应用程序的性能瓶颈,否则您很可能不想花费更多的编程精力。

This blog post on how to pass sink arguments包含了关于替代方案的更长的讨论,其结论也从“坚持按值传递”作为默认值开始。

应用于您的sizeof(T)成员示例,这表明

std::string

除了上面提到的一般性能方面,请注意,签名class MyStr { std::string m_str; public: MyStr(std::string rstr) : m_str(std::move(rstr)) {} }; 意味着MyStr::MyStr(std::string rstr)存储着以{{1}形式传递的事物的真实副本。 }。这可以帮助用户了解如何使用MyStr

答案 2 :(得分:0)

正如clonk所说,您需要确切指定您想要什么。您在寻找性能还是其他东西?

另外,您可以使用编译器浏览器对此进行比较

https://godbolt.org/

在编译器浏览器中编写代码,它将自动生成汇编代码。当然,您可以选择编译器。

答案 3 :(得分:0)

完整答案:Analysing the Cases

相关问题