为什么局部变量的常数抑制返回值的移动语义? [英] Why would const-ness of a local variable inhibit move semantics for the returned value?

查看:185
本文介绍了为什么局部变量的常数抑制返回值的移动语义?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

struct STest : public boost::noncopyable {
    STest(STest && test) : m_n( std::move(test.m_n) ) {}
    explicit STest(int n) : m_n(n) {}
    int m_n;
};

STest FuncUsingConst(int n) {
    STest const a(n);
    return a;
}

STest FuncWithoutConst(int n) {
    STest a(n);
    return a;
}

void Caller() {
    // 1. compiles just fine and uses move ctor
    STest s1( FuncWithoutConst(17) );

    // 2. does not compile (cannot use move ctor, tries to use copy ctor)
    STest s2( FuncUsingConst(17) );
}

上面的例子说明了如何在C ++ 11中, C ++ 2012中,函数的内部细节可以修改其返回类型。直到今天,我的理解是,返回类型的声明是所有程序员需要知道的,以了解如何处理返回值,例如作为参数传递到后续函数调用时。 不是这样。

The above example illustrates how in C++11, as implemented in Microsoft Visual C++ 2012, the internal details of a function can modify its return type. Up until today, it was my understanding that the declaration of the return type is all a programmer needs to know to understand how the return value will be treated, e.g., when passed as a parameter to a subsequent function call. Not so.

我喜欢在适当的地方创建局部变量 const 它帮助我清理我的思想,清楚地构建一个算法。但要注意返回一个声明为 const 的变量!即使变量不再被访问(一个 return 语句被执行),即使被声明为 const 已经超出范围(参数表达式的计算已完成),它不能被移动,因此将被复制(或者如果复制不可能,则无法编译)。

I like making local variables const where appropriate. It helps me clean up my train of thought and clearly structure an algorithm. But beware of returning a variable that was declared const! Even though the variable will no longer be accessed (a return statement was executed, after all), and even though the variable that was declared const has long gone out of scope (evaluation of the parameter expression is complete), it cannot be moved and thus will be copied (or fail to compile if copying is not possible).

此问题与另一个问题相关,移动语义&返回const值。不同的是,在后者中,函数声明返回一个 const 值。在我的例子中, FuncUsingConst 被声明为返回一个volatile临时。然而,函数体的实现细节影响返回值的类型,并确定返回的值是否可以用作其他函数的参数。

This question is related to another question, Move semantics & returning const values. The difference is that in the latter, the function is declared to return a const value. In my example, FuncUsingConst is declared to return a volatile temporary. Yet, the implementational details of the function body affect the type of the return value, and determine whether or not the returned value can be used as a parameter to other functions.

标准是否符合此行为?

如何才能有效?

奖金问题:编译器如何调用和实现可能在不同的翻译单元中,编译器如何知道差异?

Bonus question: How can the compiler know the difference at compile time, given that the call and the implementation may be in different translation units?

编辑:试图重新整理问题。

An attempt to rephrase the question.

一个函数的结果如何可能比声明的返回类型更多?它甚至看起来似乎都是可接受的,函数声明不足以确定函数的返回值的行为?对我来说,似乎是一个FUBAR的情况,我只是不知道是否应该归咎于标准或微软的实现。

How is it possible that there is more to the result of a function than the declared return type? How does it even seem acceptable at all that the function declaration is not sufficient to determine the behavior of the function's returned value? To me that seems to be a case of FUBAR and I'm just not sure whether to blame the standard or Microsoft's implementation thereof.

作为被调用函数的实现,我不能指望甚至知道所有调用者,更不用说监视调用代码中的每一个小的变化。另一方面,作为调用函数的实现者,我不能依赖被调用的函数不返回在函数实现范围内恰好被声明为const的变量。

As the implementer of the called function, I cannot be expected to even know all callers, let alone monitor every little change in the calling code. On the other hand, as the implementer of the calling function, I cannot rely on the called function to not return a variable that happens to be declared const within the scope of the function implementation.

函数声明是一个合约。现在值得吗?我们不是在这里讨论一个语义上等效的编译器优化,如复制elision,这是很好,但不改变代码的意义。无论是否调用copy ctor,都会改变代码的含义(甚至可能将代码破坏到无法编译的程度,如上所述)。要感谢我在这里讨论的尴尬,请考虑上面的奖金问题。

A function declaration is a contract. What is it worth now? We are not talking about a semantically equivalent compiler optimization here, like copy elision, which is nice to have but does not change the meaning of code. Whether or not the copy ctor is called does change the meaning of code (and can even break the code to a degree that it cannot be compiled, as illustrated above). To appreciate the awkwardness of what I am discussing here, consider the "bonus question" above.

推荐答案


如果一个对象的复制/移动构造函数[...]被隐式地使用并且不能访问特殊成员函数,则程序是不成形的

A program is ill-formed if the copy/move constructor [...] for an object is implicitly odr-used and the special member function is not accessible

- n3485 C ++草案标准[class.copy] / 30

-- n3485 C++ draft standard [class.copy]/30

我怀疑你的问题是在MSVC 2012,而不是C + 11。

I suspect your problem is with MSVC 2012, and not with C++11.

这段代码即使不调用它也不合法C ++ 11:

This code, even without calling it, is not legal C++11:

struct STest {
  STest(STest const&) = delete
  STest(STest && test) : m_n( std::move(test.m_n) ) {}
  explicit STest(int n) : m_n(n) {}
  int m_n;
};

STest FuncUsingConst(int n) {
  STest const a(n);
  return a;
}

,因为没有合法的方法转换 / code>转换为返回值。

because there is no legal way to turn a into a return value. While the return can be elided, eliding the return value does not remove the requirement that the copy constructor exist.

如果MSVC2012允许 FuncUsingConst

If MSVC2012 is allowing FuncUsingConst to compile, it is doing so in violation of the C++11 standard.

这篇关于为什么局部变量的常数抑制返回值的移动语义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆