【问题标题】:What happens if I return literal instead of declared std::string?如果我返回文字而不是声明的 std::string 会发生什么?
【发布时间】:2012-12-13 10:16:24
【问题描述】:

假设我们有一个效用函数:

std::string GetDescription() { return "The description."; }

返回字符串字面量可以吗?隐式创建的std::string 对象是否被复制?

我想过总是这样退货:

std::string GetDescription() { return std::move(std::string("The description.")); }

但它当然更长更冗长。我们也可以假设编译器 RVO 会对我们有所帮助

std::string GetDescription() { return std::string("The description."); }

然而,我不知道它真正必须做什么,而不是可以做什么。

【问题讨论】:

    标签: c++ c++11


    【解决方案1】:
    std::string GetDescription() { return "XYZ"; }
    

    等价于:

    std::string GetDescription() { return std::string("XYZ"); }
    

    这又相当于:

    std::string GetDescription() { return std::move(std::string("XYZ")); }
    

    意味着当您返回std::string("XYZ") 这是一个临时对象时,std::move 是不必要的,因为该对象将被移动无论如何(隐式)。

    同样,当您返回"XYZ" 时,显式构造std::string("XYZ") 是不必要的,因为构造无论如何都会发生(隐式)。


    所以这个问题的答案:

    隐式创建的 std::string 对象是否被复制?

    否。隐式创建的对象毕竟是(隐式)移动的临时对象。但是编译器可以忽略这个动作!

    所以底线是这样的:你可以编写这段代码并且很开心:

    std::string GetDescription() { return "XYZ"; }
    

    在某些极端情况下,return tempObjreturn std::move(tempObj) 更有效(因此更好)。

    【讨论】:

    • move 是不必要的,构造的字符串是临时的。
    • 移动的要求是,只要允许复制省略,C++11 要求编译器使用移动构造函数(如果有的话)。然后可以根据编译器的选择省略该移动(就像副本一样)。当然,在一个明智的编译器中它会是,所以很可能“是临时复制的”和“临时移动的”的答案都是“否”。名义上它是移动的,实际上移动被省略了,返回值是使用字面量构造的。
    • @SteveJessop:但语义它是移动(即使它被省略了),不是吗?
    • @Nawaz:好吧,我说的是“名义上的移动”而不是“语义上的移动”。某些类的语义根据移动是否实际被省略(如果移动构造函数有副作用)而有所不同。但我绝对同意你的观点,在 C++11 中,如果类型有移动构造函数(字符串有),则不允许复制。所以可以省略的东西是移动而不是复制。
    • @Nawaz:顺便说一句,std::move 抑制省略的原因是允许从临时的省略如果没有对临时的引用。但是move 确实引用了临时文件。所以在某些情况下move 是一种悲观(如果你将它应用到一个移动成本很高的对象上,如果你不理会它就会被忽略)。并不是说string 的移动成本很高。
    【解决方案2】:

    返回字符串字面量可以吗?隐式创建的 std::string 对象是否被复制?

    没关系。你得到的是 std::string 的(隐式)构造函数,它创建一个本地副本,然后作为右值引用返回。将客户端代码中的结果转换为字符串,将从右值引用设置该字符串。

    如果你使用第二段代码,你“说得太多了”。代码是正确的,它们(几乎)是等价的(它们应该是等价的,但编译器在第一种情况下被允许执行的优化更好*)。

    我会去:

    std::string GetDescription() { return std::string("The description."); }
    

    通过这种方式,您可以明确返回一个字符串,并且代码(几乎)是最少的:您依赖于 std::string 移动构造。

    *) 在@SteveJessop 发表评论后进行了相应编辑。

    【讨论】:

    • “它们应该是等价的,但可能是编译器在第一种情况下可以执行的优化更好”——我相信你是对的,编译器的优化是允许的 如果没有move,性能会更好。如果您明确输入std::move,那么我认为临时文件不再符合省略的条件。所以“应该是等价的”是“在这种情况下标准应该允许移动省略”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-12
    • 2023-04-05
    • 2020-03-24
    • 2017-05-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多