C++ 为什么非常量引用不能绑定到临时对象?
为什么不允许获取对临时对象的非常量引用, 哪个函数C++ 为什么非常量引用不能绑定到临时对象?,c++,reference,constants,temporary,c++-faq,C++,Reference,Constants,Temporary,C++ Faq,为什么不允许获取对临时对象的非常量引用, 哪个函数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
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;
}
ref()
可以修改临时对象李>
ref()
允许您愚弄编译器并获得指向此临时对象的链接,从而解决了我们的问题X& x = getx().ref(); // OK
你为什么想要
X&X=getx()代码>?只需使用X=getx()代码>并依赖于RVO。“很明显,在上面的示例中,临时对象不是常量,因为调用
允许使用非常量函数。例如,ref()可以修改临时
对象。”
在您的示例中,getX()不返回常量X,因此您可以使用与调用X().ref()相同的方式调用ref()。您正在返回一个非常量引用,因此可以调用非常量方法,但不能将该引用分配给非常量引用
const X& x = getx(); // OK
连同SadSidos的评论,这使你的三点不正确。由此:
。。。C++不希望你意外
修改临时表,但直接修改
在上调用非常量成员函数
可修改的右值是显式的,因此
这是允许的
基本上,你不应该试图修改临时对象,因为它们是临时对象,随时都会消失。允许您调用非常量方法的原因是,欢迎您做一些“愚蠢”的事情,只要您知道自己在做什么,并且对它有明确的认识(例如,使用reinterpret_cast)。但是,如果将一个临时引用绑定到一个非常量引用,您可以“永远”传递它,只是为了让您对对象的操作消失,因为在过程中的某个地方,您完全忘记了这是一个临时引用
如果我是你,我会重新考虑我的功能设计。为什么g()接受引用,它会修改参数吗?如果否,则将其设置为const reference,如果是,为什么要尝试将temporary传递给它,您不在乎您正在修改的是temporary吗?为什么getx()返回的是临时的?如果您与我们分享您的真实场景以及您试图实现的目标,您可能会得到一些关于如何实现的好建议
违背语言和愚弄编译器很少能解决问题——通常它会产生问题
编辑:在评论中回答问题:
1) X&X=getx().ref();//好吧,x什么时候会死?
-我不知道也不在乎,因为这正是我所说的“违背语言”的意思。该语言说“临时变量在语句末尾死亡,除非它们绑定到常量引用,在这种情况下,当引用超出范围时,它们就会死亡”。应用该规则,似乎x在下一条语句的开头已经死了,因为它没有绑定到const reference(编译器不知道ref()返回什么)。然而,这只是一个猜测
2) 我清楚地说明了目的:不允许修改临时值,因为它根本没有意义(忽略C++0x右值引用)。“那么为什么我可以给非康斯特成员打电话?”这个问题是个好问题,但我没有比上面提到的更好的答案
3) 如果我在x&x=getx()代码>在语句的末尾,问题是显而易见的
无论如何,根据你的问题和评论,我认为即使这些额外的答案也不能让你满意。这是一个最后的尝试/总结:C++委员会决定修改临时性文件是没有意义的,因此,他们禁止绑定到非const引用。可能是一些编译器实现或历史问题也涉及,我不知道。然后,出现了一些特定的情况,并决定尽管有各种可能性,他们仍然允许通过调用non-const方法进行直接修改。但这是一个例外——通常不允许修改临时表。是的,C++经常是很奇怪的。p> 在代码中getx()
返回一个临时对象,即所谓的“rvalue”。您可以将右值复制到对象(也称为变量)中,或者将它们绑定到常量引用(这将延长它们的生命周期,直到引用的生命周期结束)。不能将右值绑定到非常量引用
这是一个经过深思熟虑的设计决策,目的是防止用户意外修改将在表达式末尾消亡的对象:
g(getx()); // g() would modify an object without anyone being able to observe
如果要执行此操作,必须先创建对象的本地副本或副本,或将其绑定到常量引用:
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++标准将包括RValk引用。因此,你们所知道的引用正被称为“左值引用”。将允许您将右值绑定到右值引用,并且可以在“右值”上重载函数:
rvalue引用背后的思想是,由于这些对象无论如何都会消亡,您可以利用这些知识实现所谓的“移动语义”,这是一种特定的优化:
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
您显示的是允许操作员链接
X& x = getx().ref(); // OK
表达式是“getx().ref();”这是在分配前完成的
// It would allow things like this.
getPipeline().procInstr(1).procInstr(2).procInstr(3);
// or more commonly
std::cout << getManiplator() << 5;
x& = const_cast<x&>(getX());
int getI() { return 5;}
int x& = getI();
x++; // Note x is an alias to a variable. What variable are you updating.
int const& y = getI();
g(getx()); //error
const X& x = getx(); // OK
X& x = getx(); // error
g(getx().ref()); //OK
g(const_cast<x&>(getX()));
// Assuming: void Person::GetNameAndAddr(std::string &name, std::string &addr);
string name;
person.GetNameAndAddr(name, string()); // don't care about addr
person.GetNameAndAddr(name,
const_cast<string &>(static_cast<const string &>(string())));
string name;
string unused;
person.GetNameAndAddr(name, unused); // don't care about addr
string name;
{
string unused;
person.GetNameAndAddr(name, unused); // don't care about addr
}
MFnDoubleArrayData myArrayData;
MObject myArrayObj = myArrayData.create(myArray);
MPlug myPlug = myNode.findPlug(attributeName);
myPlug.setValue(myArrayObj);
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;
void incr(int& a) { ++a; }
int i = 0;
incr(i); // i becomes 1
incr(0); // error: 0 is not an lvalue