0

Я пытаюсь сделать вектор из нескольких целых чисел, перегружая оператора < < и оператора преобразования. Однако, когда я проверяю свой код, я наблюдаю некоторые абсурдные результаты.vector push_back показывает абсурдный результат

Напечатанный выход должен быть 1 2 3 4.

Но на самом деле распечатать что-то вроде этого: 28495936 0 3 4.

Первые два элемента (например, 1 и 2), которые должны были вдвигаться в вектор, теряется или загрязняется.

Буду признателен, если кто-то может помочь мне разобраться в причинах этого.

#include <iostream> 
#include <vector> 

using namespace std; 

template<typename T> 
class make_vector { 
public: 
    typedef make_vector<T> my_type; 
    my_type& operator<<(const T& val) 
    { 
     data_.push_back(val); 
     return *this; 
    } 
    operator std::vector<T>&() 
    { 
     return this->data_; 
    } 

private: 
    std::vector<T> data_; 
}; 


int main() { 
    std::vector<int>& A2 = make_vector<int>() << 1 << 2 << 3 << 4; 

    for (std::vector<int>::iterator it = A2.begin(); it != A2.end(); ++it)   
    { 
     cout << *it << " "; 
    } 
    cout << endl; 
    return 0; 
} 

ответ

3

Вы связывание ссылки Lvalue к временному:

std::vector<int>& A2 = make_vector<int>() << 1 << 2 << 3 << 4; 

Обратите внимание, что, как @ T.C. упоминается в комментариях, это ваш оператор преобразования, который позволяет это. Без него вышеприведенное утверждение было бы недействительным C++.

Проблема с вашим кодом заключается в том, что после этой строки A2 относится к несуществующему объекту.

Мне кажется, вы не хотите использовать ссылку:

std::vector<int> A2 = make_vector<int>() << 1 << 2 << 3 << 4; 
+0

Я вижу проблему сейчас. Помогает! Благодарим Вас за разъяснения. – swm

+0

Вам не требуется расширение для компиляции, благодаря плохо разработанному 'operator std :: vector &()'. Это действительно должно быть ref-qualit; и 'operator <<' должен, вероятно, также иметь две рефлексивные перегрузки, чтобы сохранить категорию значений. –

+0

@ T.C. Я полностью пропустил это. Благодаря! – juanchopanza

1

Вы имеете повисшую ссылку здесь. Он ссылается на временный.

std::vector<int>& A2 = make_vector<int>().... 

У вас есть два варианта:

Вы можете скопировать ТЕмп в новую локальную переменную.

std::vector<int> A2 = make_vector<int>().... 

Или использовать const реф. C++ предоставляет специальное правило, позволяющее ссылаться на ссылки на const для продления срока службы временного.

const std::vector<int>& A2 = make_vector<int>().... 
+0

Получил это. Спасибо, Дрю. – swm

+0

@ пользователь1487243 хороший. Удачи! –

+1

const ref не работает. Вы привязываетесь к возвращаемому значению функции-члена, а не к временному; что не продлевает срок службы. –

0

Ваш make_vector плохо разработан и опасно. Вы сделали его конвертируемым в std::vector<T>& со ссылкой на его член vector, даже если объект make_vector является временным. Это оборванная ссылка ждет, чтобы это произошло, так как с этой установкой компилятор не будет жаловаться, когда вы делаете вещи, как

std::vector<int>& A2 = make_vector<int>() << 1 << 2 << 3 << 4; 

, потому что все в этой линии вполне допустимо. За исключением того, что он оставляет A2 обвисшую ссылку, поскольку make_vector временно - и содержащийся в нем вектор - уничтожается на ;. Уч.

Лучший дизайн бы реф-квалифицировать и перегружать operator<< и функция преобразования:

my_type& operator<<(const T& val) & 
{ 
    data_.push_back(val); 
    return *this; 
} 
my_type&& operator<<(const T& val) && 
{ 
    data_.push_back(val); 
    return std::move(*this); 
} 

operator std::vector<T>&() & 
{ 
    return this->data_; 
} 

operator std::vector<T>() && 
{ 
    return std::move(this->data_); 
} 

Во-первых, мы делаем только именующее make_vector s раскладывается в Lvalue ссылкой на основной вектор, так как это, вероятно, безопасно , Для rvalue make_vector s, таких как временные, мы делаем функцию преобразования, возвращающую вектор по значению, перемещаясь от базового вектора.

Во-вторых, мы перегружать operator<< сохранить категорию ценностный make_vector объекта, вызывается на - он возвращает Lvalue ссылку, если ссылаться на Lvalue и ссылку RValue если ссылаться на RValue. Таким образом, make_vector<int>() << 1 << 2 << 3 << 4 остается rvalue.

Теперь ошибки, как std::vector<int>& A2 = make_vector<int>() << 1 << 2 << 3 << 4; не будет компилировать, в то время как

std::vector<int> A2 = make_vector<int>() << 1 << 2 << 3 << 4; 

и

const std::vector<int> & A2 = make_vector<int>() << 1 << 2 << 3 << 4; 

воля и оба являются безопасными. (Во втором случае ссылка const привязывается к временному возврату operator std::vector<int>(), что продлевает срок службы временного.)

+0

T.C., я очень ценю ваш ответ. Для меня достаточно информации для переваривания и изучения. Я буду уверен, что смогу проголосовать за этот ответ после того, как я получу достаточную репутацию позже. – swm

+0

следует перенести первую функцию преобразования в оператор std :: vector () &? – swm

+0

@ пользователь1487243 Не требуется; Дело в том, что когда объект является lvalue, возвращение ссылки безопасно. –