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

3
以下是一个具有一个字符串成员的类。我们希望在构造函数中初始化它:
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) };

5
取决于你想要做什么。所有初始化字符串的方式都是有效的。"更好"是相对的。更好的性能?更好的代码可读性? - Clonk
4个回答

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”

最易读的是... 嗯,几乎任何其他东西 ;) - Quentin
除非必要,否则我会省略enable_if - Caleth
@Caleth 如果没有使用 enable_if,那么构造函数会被用于不能转换为字符串的事物。 - Maxim Egorushkin
不,尝试这样做会导致一个严重的错误。目前尝试这样做也会导致一个严重的错误,因此没有任何改变。您可以使用enable_if在错误消息中删除一个模板深度。 - Caleth
@Caleth当添加其他构造函数时,此构造函数将优先选择其他构造函数。 这就是为什么它需要限制其接受的内容。 观看那个视频以获取更多见解。 - Maxim Egorushkin
这就是当我说“除非有必要”时的意思。 - Caleth

1

这里有一个更为通用的实用经验法则:

将所有“便宜可移动”的下沉参数按值传递,并在适当时使用 std::move

典型的不是“便宜可移动”的类型包括: std::array 和其他 T 类型,其中 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) 意味着MyStr 正在存储作为rstr传递的内容的实际副本。这可以帮助用户理解应该如何使用< code>MyStr 。

0

正如clonk所说,您需要明确您想要什么。您是在寻找性能还是其他方面的东西?

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

https://godbolt.org/

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


1
这并没有真正回答问题,应该是一条评论。 - HolyBlackCat

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接