为什么不允许获取临时对象的非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

当前回答

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

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

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

其他回答

这篇关于右值引用的Visual c++博客文章:

... c++不希望你意外地 修改临时对象,但是要直接修改 在上调用非const成员函数 可修改的右值是显式的,所以 这是允许的……

Basically, you shouldn't try to modify temporaries for the very reason that they are temporary objects and will die any moment now. The reason you are allowed to call non-const methods is that, well, you are welcome to do some "stupid" things as long as you know what you are doing and you are explicit about it (like, using reinterpret_cast). But if you bind a temporary to a non-const reference, you can keep passing it around "forever" just to have your manipulation of the object disappear, because somewhere along the way you completely forgot this was a temporary.

如果我是你,我会重新考虑我的功能设计。为什么g()接受引用,它修改参数了吗?如果不是,使它const引用,如果是,为什么你试图传递临时给它,你不在乎它是一个临时你正在修改?为什么getx()返回临时的?如果你和我们分享你的真实情况以及你想要实现的目标,你可能会得到一些关于如何做到这一点的好建议。

违背语言和愚弄编译器很少能解决问题——通常它会制造问题。


Edit: Addressing questions in comment: 1) `X& x = getx().ref(); // OK when will x die?` - I don't know and I don't care, because this is exactly what I mean by "going against the language". The language says "temporaries die at the end of the statement, unless they are bound to const reference, in which case they die when the reference goes out of scope". Applying that rule, it seems x is already dead at the beginning of the next statement, since it's not bound to const reference (the compiler doesn't know what ref() returns). This is just a guess however.

我清楚地说明了目的:不允许修改临时对象,因为这没有意义(忽略c++ 0x右值引用)。“那么为什么允许我调用非const成员?”这个问题很好,但我没有比上面已经提到的更好的答案了。 好吧,如果我对x中的x是正确的& x = getx().ref();在声明的最后,问题是显而易见的。

Anyway, based on your question and comments I don't think even these extra answers will satisfy you. Here is a final attempt/summary: The C++ committee decided it doesn't make sense to modify temporaries, therefore, they disallowed binding to non-const references. May be some compiler implementation or historic issues were also involved, I don't know. Then, some specific case emerged, and it was decided that against all odds, they will still allow direct modification through calling non-const method. But that's an exception - you are generally not allowed to modify temporaries. Yes, C++ is often that weird.

主要的问题是

g(getx()); //error

是一个逻辑错误:g正在修改getx()的结果,但您没有任何机会检查修改后的对象。如果g不需要修改形参,那么它就不需要左值引用,它可以通过value或const引用获取形参。

const X& x = getx(); // OK

有效,因为有时需要重用表达式的结果,而且很明显您正在处理一个临时对象。

然而,这是不可能的

X& x = getx(); // error

有效而不使g(getx())有效,这是语言设计者首先试图避免的。

g(getx().ref()); //OK

是有效的,因为方法只知道this的const性,它们不知道它们是在左值上调用还是在右值上调用。

就像在c++中一样,你有一个解决这个规则的方法,但是你必须显式地告诉编译器你知道你在做什么:

g(const_cast<x&>(getX()));

我想分享一个场景,我希望我能做到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描述的例子。欢迎大家的批评和建议!

谢谢。

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

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

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

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