【问题标题】:Move semantics & returning const values移动语义和返回 const 值
【发布时间】:2011-08-21 14:18:31
【问题描述】:

我有将所有内容作为“const”值返回的习惯(?!?!?)。像这样……

struct s;

s const make_s();

s const &s0 = make_s();
s const s1 = make_s();

具有移动操作和右值引用以及以下功能...

void take_s(s &&s0);
void take_s(s const &&s0);  //  Doesn't make sense

我写不下去了……

take_s(make_s());

我开始使用返回 const 值的约定的主要原因是为了防止有人编写这样的代码...

make_s().mutating_member_function();

用例如下...

struct c_str_proxy {
    std::string m_s;

    c_str_proxy(std::string &&s) : m_s(std::move(s)) {
    }
};

c_str_proxy c_str(std::string &&s) {
    return c_str_proxy(s);
}

char const * const c_str(std::string const &s) {
    return s.c_str();
}

std::vector < std::string > const &v = make_v();
std::puts(c_str(boost::join(v, ", ")));

std::string const my_join(std::vector < std::string > const &v, char const *sep);

//  THE FOLLOWING WORKS, BUT I THINK THAT IS ACCIDENTAL
//  IT CALLS
//
//      c_str(std::string const &);
//
//  BUT I THINK THE TEMPORARY RETURNED BY
//
//      my_join(v, "; ")
//
//  IS NO LONGER ALIVE BY THE TIME WE ARE INSIDE
//
//      std::puts
//
//  AS WE ARE TAKING THE "c_str()" OF A TEMPORARY "std::string"
//
std::puts(c_str(my_join(v, "; ")));

看起来好像“返回 const 值”和 r 值引用在这个特定用例中没有混合使用。对吗?

**Edit 0: Extra question...**

无论如何,该对象是临时的。为什么“const”应该阻止移动?为什么我们不能移动“const”临时对象?

【问题讨论】:

  • 我并没有真正看到首先返回 const 值的理由。为什么要关心防止人们在返回的对象上调用变异成员函数?
  • 可以在 Meyers, "More Effective c++", 1996, Item 6 中找到一个 const value return idiom 的例子。Meyers 推荐 const T operator++(int) 作为 postfix++ 的签名。

标签: c++ c++11 constants return-value move-semantics


【解决方案1】:

您有两个相互冲突的目标。一方面,您希望防止对返回的对象进行修改,但另一方面,您希望允许进行修改(这就是一个动作操作是。它通过窃取其内部资源来修改源对象。

你需要下定决心。您希望对象是不可变的,还是希望人们能够修改它?

对于它的价值,我真的不知道首先返回 const 临时变量会获得什么。是的,您阻止人们对其调用变异成员函数,但是为什么要这样做?最好的情况是,能够这样做是有用的,最坏的情况是,这是一个很容易避免的错误。

而你所做的并没有多大意义。 临时的全部意义在于它马上就会消失,所以谁在乎它是否被修改?

右值引用和移动语义背后的整个想法是临时对象是临时的,因此可以在不伤害任何人的情况下对其进行修改。

【讨论】:

  • 是的。您想要返回 const 的唯一情况是当它是引用或指向您不希望调用者能够更改的对象的指针时。否则,让他们改变。
  • 实际上,返回 const rvalues 有助于防止以下错误: if (a * b = c) if a*b 的类型可以用 c 赋值并且可以隐式转换为 bool... .这是一个边缘情况,但很容易通过将用户类型返回为 const 来避免。在 vc14 编译器上测试我看到一个函数返回的 const rvalue 仍然被发送到移动构造函数。 C++14 中是否有任何新内容指定了这一点,或者这只是编译器特定的优化?
【解决方案2】:

您实际上可能会遇到局部变量超出范围的问题。

c_str()返回一个指向内部缓冲区的指针,所以一旦原始变量超出范围,该指针就会失效。

【讨论】:

  • 我知道这一点,但问题实际上是关于返回 const 值。我猜即使使用 r 值引用,返回 const 值也会阻止移动。我以前认为是好的做法突然不正确了。
【解决方案3】:

返回值上的 const 限定符没有语义。如果您在编译器上调高警告级别,每次执行此操作时都会发出警告。

【讨论】:

  • 这作为一般性陈述是绝对不正确的。也许您可以澄清或提供您所谈论的具体内容的参考?
猜你喜欢
  • 1970-01-01
  • 2013-04-11
  • 2018-12-15
  • 1970-01-01
  • 2014-09-19
  • 1970-01-01
  • 1970-01-01
  • 2013-06-08
  • 2018-08-03
相关资源
最近更新 更多