I had this problem while using a given library in my software. A function returns a const std::vector&
which I want to use. However, the first value is always set to zero (or in my original code: a 3D-vector with all coordinates set to 0.0) although the value I stored in it beforehand was not.
The class structure is the following (the example code is below):
ValueContainer
: contains a std::vector< double >
of values and the getter values()
.Object
: contains a ValueContainer
, and a getter valuesContainer()
.In my code, I retrieved the values with:
// First element always set to 0
const std::vector< double >& values = object.valuesContainer().values();
This resulted in the error, that the first element was set to 0.0
.
I could circumvent the problem by copying the values:
// This works as expected
std::vector< double > values = object.valuesContainer().values();
On closer inspection, I noticed, that valuesContainer()
did not return a reference, but a copy of ValueContainer
. What happens is (in my understanding), that I call values()
on a temporary object created by valuesContainer()
and thus get a reference to a temporary object. This of course will not work well, and I would expect to get 'garbage'-data in my vector, or something like that.
However: All the values except the first one seem to be ok! Now, the real question is: Why does it work like that? If it is just undefined behaviour, why is the first value set to 0 and the others remain the same? I'd be happy to get a little more insight into that matter.
Here now follows the example code, tested with gcc 4.8.1 on linux:
#include <iostream>
#include <iomanip>
#include <vector>
class ValueContainer
{
public:
ValueContainer();
inline const std::vector< double >& values() const;
//private:
std::vector< double > some_values_;
};
class Object
{
public:
ValueContainer valueContainerCopy() const
{
return values_;
}
const ValueContainer& valueContainerConstRef() const
{
return values_;
}
//private:
ValueContainer values_;
};
ValueContainer::ValueContainer()
{
// Just some test data
some_values_.push_back(1.2);
some_values_.push_back(3.4);
some_values_.push_back(5.6);
some_values_.push_back(7.8);
some_values_.push_back(9.0);
}
const std::vector< double >& ValueContainer::values() const
{
return some_values_;
}
int main( int argc, char** argv )
{
Object obj;
const std::vector< double >& values_CopyRef = obj.valueContainerCopy().values();
const std::vector< double >& values_RefRef = obj.valueContainerConstRef().values();
std::vector< double > values_CopyCopy = obj.valueContainerCopy().values();
std::cout << "Pointers: " << std::endl
<< " - Original: " << &obj.values_.some_values_ << std::endl
<< " - CopyRef: " << &values_CopyRef << std::endl
<< " - RefRef: " << &values_RefRef << std::endl
<< " - CopyCopy: " << &values_CopyCopy << std::endl;
std::cout << "Data pointers: " << std::endl
<< " - Original: " << obj.values_.some_values_.data() << std::endl
<< " - CopyRef: " << values_CopyRef.data() << std::endl
<< " - RefRef: " << values_RefRef.data() << std::endl
<< " - CopyCopy: " << values_CopyCopy.data() << std::endl;
std::cout << "Data:" << std::endl;
for ( std::size_t i = 0; i < values_RefRef.size(); i++ )
{
std::cout << "i=" << i << ": " << std::fixed << std::setprecision(1)
<< "CopyRef: " << values_CopyRef[ i ] << ", "
<< "RefRef: " << values_RefRef[ i ] << ", "
<< "CopyCopy: " << values_CopyCopy[ i ]
<< std::endl;
}
return 0;
}
The (important) output of this example is the following, where you can see, that the first value of the reference to the temporary object is set to 0 and the other values seem fine:
i=0: CopyRef: 0.0, RefRef: 1.2, CopyCopy: 1.2
i=1: CopyRef: 3.4, RefRef: 3.4, CopyCopy: 3.4
i=2: CopyRef: 5.6, RefRef: 5.6, CopyCopy: 5.6
i=3: CopyRef: 7.8, RefRef: 7.8, CopyCopy: 7.8
i=4: CopyRef: 9.0, RefRef: 9.0, CopyCopy: 9.0
const std::vector< double >& values_CopyRef = obj.valueContainerCopy().values();
That is storing a reference to a temporary because the valueContainerCopy
function is declared as
ValueContainer valueContainerCopy() const
{
return values_;
}
Which will copy the vector values_
into a temporary vector that is returned. You are then storing a reference to data in that temporary, resulting in undefined behavior.
If you want to store it as a reference, you need to return a reference, which is what you do in the valueContainerConstRef
function.