Why does the C++ compiler generate a temporary here?
The following class is intended to monitor the changing state of another process; its constructor sets up const references to facilitate access to the relevant variables. Here's The ctor code:
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;
};
The class data members of interest are the two const int references iMyEdge and iNeighborEdge, initialized as
iMyEdge(edgeBar(me,facingNeighbor)), iNeighborEdge(edgeBar(neighbor,facingMe)),
and the 3 const float references myEdgeVal, neighborEdgeVal, myPeakVal, initialized as
myEdgeVal(me[facingNeighbor].datum()),
neighborEdgeVal(neighbor[facingMe].datum()),
my开发者_JAVA技巧PeakVal(me[PEAK_V].datum()),
In the former case (the ints) the references work as expected. In the floats case, the compiler gives the message
"warning C4413: 'MergeableHeight::myEdgeVal' : reference member is initialized to a temporary that doesn't persist after the constructor exits," and similarly for the other two floats.
The user-defined DDBuffer type encapsulates a vector with a fixed number of DataDescriptors -- another user-defined type. DataDescriptor provides the member function datum(),
const float& datum()const {return _datum;}
while DDBuffer provides the [] operator,
const DatumDescriptor& operator[](int i)const {return buffer.at(i);}
DatumDescriptor& operator[](int i) {return buffer.at(i);} //const & non-const versions
Since everthing returns references, why on earth is a temporary being created here? In particular, the whole point is that the state variables should reflect the actual values in the references passed to the ctor, so I certainly wouldn't want a temporary created even if it was to remain in scope.
What am I missing??
datum()
returns a const float&
and your variable is a const double&
. You cannot convert one to the other, hence the temporary.
myEdgeVal
is a reference to the data stored in me
which is passed to the constructor. As me
is itself a const reference, it could be a temporary variable. If it is, then myEdgeVal
would be a reference to something inside an object that's destroyed after the constructor completes.
How do you construct the MergeableHeight
object in your code?
Also, as all of those member int/double variables are constant, there is no need to make them references.
Sure, me
is a ref-to-const
, and so is the result of me[facingNeighbor].datum()
.
However, the latter is a const float&
and you're trying to bind it to a const double&
, requiring a conversion. This produces a temporary, and it's one that exists only in the scope of the constructor.
Though its lifetime can be extended in higher stack frames (by binding to ref-to-const
, as you know) it cannot magically be brought into lower stack frames.
Consider:
int foo();
const int& x = foo(); // valid; the result of foo() may exist as long as x does
But:
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.
精彩评论