0

在我的软件中使用给定库时遇到了这个问题。一个函数返回一个const std::vector&我想使用的。但是,第一个值始终设置为零(或在我的原始代码中:所有坐标设置为 0.0 的 3D 向量),尽管我事先存储在其中的值不是。

类结构如下(示例代码如下):

  • ValueContainer: 包含一个std::vector< double >值和 getter values()
  • Object: 包含一个ValueContainer, 和一个 getter valuesContainer()

在我的代码中,我检索了以下值:

// First element always set to 0
const std::vector< double >& values = object.valuesContainer().values();

这导致了错误,即第一个元素设置为0.0. 我可以通过复制值来规避这个问题:

// This works as expected
std::vector< double > values = object.valuesContainer().values();

仔细检查后,我注意到,它valuesContainer()没有返回参考,而是ValueContainer. 发生的事情是(在我的理解中),我调用values()了一个由创建的临时对象valuesContainer(),从而获得了对临时对象的引用。这当然不能很好地工作,我希望在我的向量中得到“垃圾”数据,或者类似的东西。

但是:除了第一个值之外的所有值似乎都可以!现在,真正的问题是:为什么它会这样工作?如果只是未定义的行为,为什么第一个值设置为 0 而其他值保持不变?我很乐意对这件事有更多的了解。

下面是示例代码,在 linux 上使用 gcc 4.8.1 进行了测试:

#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;
}

此示例的(重要)输出如下,您可以在其中看到,对临时对象的引用的第一个值设置为 0,而其他值似乎很好:

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
4

1 回答 1

2
const std::vector< double >& values_CopyRef  = obj.valueContainerCopy().values();

那是存储对临时的引用,因为该valueContainerCopy函数被声明为

ValueContainer valueContainerCopy() const
{
    return values_;
}

这会将向量复制values_到返回的临时向量中。然后,您将在该临时文件中存储对数据的引用,从而导致未定义的行为。

如果要将其存储为引用,则需要返回引用,这就是您在valueContainerConstRef函数中所做的。

于 2013-10-25T14:39:46.123 回答