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

当前回答

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

其他回答

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

问得好,下面是我试图给出的一个更简洁的答案(因为很多有用的信息都在评论中,很难在嘈杂中挖掘出来)。

任何直接绑定到临时的引用都将延长其寿命[12.2.5]。另一方面,由另一个引用初始化的引用则不会(即使它最终是相同的临时引用)。这是有意义的(编译器不知道该引用最终指向什么)。

但这整个想法非常令人困惑。例如const X &x = X();const x &x = x ().ref();will NOT(谁知道ref()实际返回了什么)。在后一种情况下,X的析构函数在这一行的末尾被调用。(这可以通过非平凡析构函数观察到。)

因此,这通常看起来是令人困惑和危险的(为什么要把关于对象生存期的规则复杂化呢?),但至少需要const引用,所以标准确实为它们设置了这种行为。

[来自sbi comment]:请注意,将其绑定到const引用可以增强a Temporary的生命周期是一个故意添加的异常 (TTBOMK,以便允许手动优化)。没有 为非const引用添加的异常,因为绑定是临时的 对非const的引用被认为最有可能是程序员 错误。

所有临时变量都将持续到完整表达式结束。然而,要使用它们,就需要像使用ref()一样的技巧。这是合法的。除了提醒程序员正在发生一些不寻常的事情(即,一个引用形参的修改很快就会丢失)之外,似乎没有什么好的理由来跳过这个额外的箍。

[另一个sbi评论]Stroustrup给出的(在D&E中)不允许绑定的原因 对非const引用的右值是,如果Alexey的g()会修改 对象(可以从接受非const参数的函数中得到) 引用),它会修改一个即将死亡的对象,所以没有人 无论如何都可以得到修改后的值。他说,这是最 很可能,是一个错误。

在代码中,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

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

您所展示的是操作符链接是允许的。

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

表达式是'getx().ref();',在赋值给'x'之前执行完成。

注意,getx()并不返回引用,而是返回一个进入本地上下文中的完整形式的对象。对象是临时的,但它不是const,因此允许您调用其他方法来计算值或发生其他副作用。

// It would allow things like this.
getPipeline().procInstr(1).procInstr(2).procInstr(3);

// or more commonly
std::cout << getManiplator() << 5;

请看这个答案的最后一个更好的例子

您不能将临时对象绑定到引用,因为这样做将生成对对象的引用,该对象将在表达式的末尾被销毁,从而留给您一个悬空引用(这是不整洁的,标准不喜欢不整洁)。

由ref()返回的值是一个有效的引用,但该方法并不关注它所返回的对象的生命周期(因为它不能在其上下文中拥有该信息)。你所做的基本上相当于:

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

对临时对象的const引用可以这样做的原因是,标准将临时对象的生命周期延长到引用的生命周期,因此临时对象的生命周期延长到语句结束之后。

那么剩下的唯一问题是,为什么标准不允许引用临时对象来将对象的生命延长到语句结束之后呢?

我相信这是因为这样做会使编译器很难得到正确的临时对象。这样做是为了对临时对象的const引用,因为它的用途有限,因此迫使你复制对象来做任何有用的事情,但确实提供了一些有限的功能。

想想这种情况:

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();

将为您提供易于使用和理解的代码。

如果你想修改值,你应该将值返回给一个变量。如果您试图避免从函数中复制对象的代价(因为看起来对象是复制构造回来的(技术上它是))。那就不用麻烦了编译器很擅长"返回值优化"