为什么C ++编译器在这里生成一个临时的?

时间:2011-08-15 09:46:33

标签: c++

以下类用于监视另一个进程的更改状态;它的构造函数设置const引用以便于访问相关变量。这是代码:

template<typename FZYRSRC>
struct MergeableHeight: public FzyQty<FZYRSRC>
{
MergeableHeight( 
    const DDBuffer& me, const DDBuffer& neighbor, Orientation ori, bool useV =false)
: iP(me[PEAK_V].index()), iNP(neighbor[PEAK_V].index()),
  facingNeighbor(iP < iNP ? RIGHT_V : LEFT_V),  //vertex pointing to neighbor
  facingMe(iP < iNP ? LEFT_V : RIGHT_V),        //neighbor's vertex pointing to me
  iMyEdge(edgeBar(me,facingNeighbor)), iNeighborEdge(edgeBar(neighbor,facingMe)),
  myEdgeVal(me[facingNeighbor].datum()), neighborEdgeVal(neighbor[facingMe].datum()),
  myPeakVal(me[PEAK_V].datum()), useVolatility(useV),o(ori)             
{} 

 //member functions etc.
 private:
      virtual MergeableHeight* clone()const {return new MergeableHeight(*this);}
const int &iP, &iNP;
const PeakVertex facingNeighbor, facingMe; //PeakVertex is Enum {LEFT_V,PEAK_V,RIGHT_V} 
const int &iMyEdge, &iNeighborEdge;
const double &myEdgeVal, &neighborEdgeVal, &myPeakVal;
const Orientation o;
bool useVolatility;
  };

感兴趣的类数据成员是两个const int引用iMyEdge和iNeighborEdge,初始化为

  iMyEdge(edgeBar(me,facingNeighbor)), iNeighborEdge(edgeBar(neighbor,facingMe)),

并且3 const float引用myEdgeVal,neighborEdgeVal,myPeakVal,初始化为

  myEdgeVal(me[facingNeighbor].datum()), 
  neighborEdgeVal(neighbor[facingMe].datum()),
  myPeakVal(me[PEAK_V].datum()),

在前一种情况(整体)中,引用按预期工作。在浮点数的情况下,编译器给出消息

“警告C4413:'MergeableHeight :: myEdgeVal':引用成员被初始化为一个在构造函数退出后不会持久存在的临时成员,”并且类似于其他两个浮点数。

用户定义的DDBuffer类型封装了一个具有固定数量DataDescriptors的向量 - 另一个用户定义的类型。 DataDescriptor提供成员函数datum(),

const float& datum()const {return _datum;}

当DDBuffer提供[]运算符时,

const DatumDescriptor& operator[](int i)const {return buffer.at(i);}
DatumDescriptor& operator[](int i) {return buffer.at(i);} //const & non-const versions

由于everthing返回引用,为什么在这里创建一个临时的?特别是,重点是状态变量应该反映传递给ctor的引用中的实际值,所以我当然不希望临时创建,即使它仍然在范围内。

我错过了什么?

3 个答案:

答案 0 :(得分:10)

datum()返回const float&,您的变量为const double&。你不能将一个转换为另一个,因此是临时的。

答案 1 :(得分:1)

myEdgeVal是对me中存储的数据的引用,该数据传递给构造函数。由于me本身是一个const引用,因此可以是一个临时变量。如果是,那么myEdgeVal将是对构造函数完成后销毁的对象内部内容的引用。

如何在代码中构造MergeableHeight对象?

此外,由于所有成员int / double变量都是常量,因此不需要对它们进行引用。

答案 2 :(得分:0)

当然,me是引用 - constme[facingNeighbor].datum()的结果也是如此。

但是,后者是const float&,您尝试将其绑定到const double&,需要进行转换。这会生成一个临时的,它只存在于构造函数的范围内。

虽然它的生命周期可以在更高的堆栈帧中扩展(通过绑定到ref-to - const,如你所知)但它不能神奇地被带入较低的堆栈帧。


考虑:

int foo();
const int& x = foo(); // valid; the result of foo() may exist as long as x does

可是:

const int& foo() {
   return 5;          // not valid; returning reference to local variable
}

int x        = foo();
const int& y = foo(); // same issue.
                      // the `5` simply doesn't exist; its stack frame is gone.