为什么不允许获取临时对象的非const引用, getx()返回哪个函数?显然,这是c++标准所禁止的 但我感兴趣的是这种限制的目的,而不是参考标准。

struct X
{
    X& ref() { return *this; }
};

X getx() { return X();}

void g(X & x) {}    

int f()
{
    const X& x = getx(); // OK
    X& x = getx(); // error
    X& x = getx().ref(); // OK
    g(getx()); //error
    g(getx().ref()); //OK
    return 0;
}

很明显,对象的生存期不可能是原因,因为 c++标准不禁止对对象的常量引用。 很明显,在上面的示例中,临时对象不是常量,因为允许调用非常量函数。例如,ref()可以修改临时对象。 此外,ref()允许你欺骗编译器并获得到这个临时对象的链接,这解决了我们的问题。

此外:

他们说“给const引用赋值一个临时对象可以延长这个对象的生命周期”和“尽管没有提到非const引用”。 我还有一个问题。下面的赋值是否会延长临时对象的生命周期?

X& x = getx().ref(); // OK

当前回答

在代码中,getx()返回一个临时对象,即所谓的“右值”。你可以把右值复制到对象中(也就是。变量)或将它们绑定到const引用(这将延长它们的生命期,直到引用的生命期结束)。不能将右值绑定到非const引用。

这是一个经过深思熟虑的设计决策,以防止用户意外地修改一个将在表达式结尾死亡的对象:

g(getx()); // g() would modify an object without anyone being able to observe

如果你想这样做,你必须先创建一个对象的本地副本或将其绑定到一个const引用:

X x1 = getx();
const X& x2 = getx(); // extend lifetime of temporary to lifetime of const reference

g(x1); // fine
g(x2); // can't bind a const reference to a non-const reference

注意,下一个c++标准将包括右值引用。因此,您所知道的引用将被称为“左值引用”。你将被允许将右值绑定到右值引用,你可以在“右值”上重载函数:

void g(X&);   // #1, takes an ordinary (lvalue) reference
void g(X&&);  // #2, takes an rvalue reference

X x; 
g(x);      // calls #1
g(getx()); // calls #2
g(X());    // calls #2, too

右值引用背后的思想是,因为这些对象无论如何都会死亡,你可以利用这一知识并实现所谓的“移动语义”,一种特定的优化:

class X {
  X(X&& rhs)
    : pimpl( rhs.pimpl ) // steal rhs' data...
  {
    rhs.pimpl = NULL; // ...and leave it empty, but deconstructible
  }

  data* pimpl; // you would use a smart ptr, of course
};


X x(getx()); // x will steal the rvalue's data, leaving the temporary object empty

其他回答

为什么要在c++常见问题中讨论(粗体部分):

在c++中,非const引用可以绑定到左值,const引用可以绑定到左值或右值,但是没有任何东西可以绑定到非const右值。这是为了防止人们更改临时对象的值,因为临时对象的新值在使用之前就被销毁了。例如:

void incr(int& a) { ++a; }
int i = 0;
incr(i);    // i becomes 1
incr(0);    // error: 0 is not an lvalue

如果允许这个incr(0),要么是一些没人见过的临时值被增加,要么更糟——0的值将变成1。后者听起来很愚蠢,但实际上在早期的Fortran编译器中有一个类似的错误,即留出一个内存位置来保存值0。

很明显,在上面的示例中,临时对象不是常量,因为调用 对于非常数函数是允许的。例如,ref()可以修改临时的 对象。”

在你的例子中,getX()不会返回一个const X,所以你可以像调用X().ref()一样调用ref()。你正在返回一个非const引用,因此可以调用非const方法,你不能做的是将ref赋值给一个非const引用。

加上SadSidos的评论,这使得你的三点不正确。

为什么你想要x & x = getx();?只需使用X X = getx();并依赖RVO。

我想分享一个场景,我希望我能做到Alexey要求的事情。在一个Maya c++插件中,我必须做以下的恶作剧,以获得一个值到一个节点属性:

MFnDoubleArrayData myArrayData;
MObject myArrayObj = myArrayData.create(myArray);   
MPlug myPlug = myNode.findPlug(attributeName);
myPlug.setValue(myArrayObj);

这写起来很乏味,所以我写了以下helper函数:

MPlug operator | (MFnDependencyNode& node, MObject& attribute){
    MStatus status;
    MPlug returnValue = node.findPlug(attribute, &status);
    return returnValue;
}

void operator << (MPlug& plug, MDoubleArray& doubleArray){
    MStatus status;
    MFnDoubleArrayData doubleArrayData;
    MObject doubleArrayObject = doubleArrayData.create(doubleArray, &status);
    status = plug.setValue(doubleArrayObject);
}

现在我可以把文章开头的代码写成:

(myNode | attributeName) << myArray;

问题是它不能在Visual c++之外编译,因为它试图将从|操作符返回的临时变量绑定到<<操作符的MPlug引用。我想它是一个参考,因为这段代码被多次调用,我宁愿没有MPlug被复制这么多。我只需要临时对象存活到第二个函数结束。

这是我的情形。我只是想展示一个人们想做Alexey描述的例子。欢迎大家的批评和建议!

谢谢。

邪恶的变通方法涉及'mutable'关键字。实际上,邪恶是留给读者的练习。或者查看这里:http://www.ddj.com/cpp/184403758