2013-10-25 7 views
0

У меня была эта проблема при использовании данной библиотеки в моем программном обеспечении. Функция возвращает const std::vector&, которую я хочу использовать. Однако первое значение всегда устанавливается равным нулю (или в моем исходном коде: 3D-вектор со всеми координатами, установленными в 0.0), хотя значение, которое я сохранил в нем заранее, не было.Первый элемент возвращаемого вектора (re) установлен в 0

Класс структуры состоит в следующем (пример кода ниже):

  • ValueContainer: содержит std::vector<double> значений и геттер values().
  • Object: содержит ValueContainer и геттер 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, а остальные остаются неизменными? Я был бы рад получить немного больше информации по этому вопросу.

Вот теперь следует пример кода, тестирование с помощью GCC 4.8.1 на 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; 
} 

(важные) выход этого примера заключается в следующем, где вы можете увидеть, что первое значение из ссылка на временный объект имеет значение 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 

ответ

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

То хранит ссылку на временный, так как функция valueContainerCopy объявляются

ValueContainer valueContainerCopy() const 
{ 
    return values_; 
} 

Какой будет копировать вектор values_ во временный вектор, который возвращается. Затем вы сохраняете ссылку на данные во временном режиме, что приводит к неопределенному поведению.

Если вы хотите сохранить его в качестве ссылки, вам нужно вернуть ссылку, что вы делаете в функции valueContainerConstRef.

+0

Я знал это, но все же спасибо за ответ. Но мне все же хотелось бы знать, почему именно в первой позиции в векторе (или в позиции памяти, где раньше использовался первый элемент временного вектора). И хотя «неопределенное поведение» может быть ответом, это на самом деле не удовлетворяет мое любопытство;) Может ли это иметь что-то. делать с уничтожением вектора темрира? – Hanno

+0

Простой ответ - неопределенное поведение не определено. Как пару других участников сказали бы: он может заказать вам пиццу ... поскольку она не определена, все, что происходит, будет «правильным» для этой системы. –