2014-12-31 3 views
1

Подпись vector::push_back является:вектор :: push_back преобразование Тип конструкции * ввести *

void push_back (const value_type& val); 

, который означает, что он несет ответственность за не развращает val.

Моя функция:

Result User::addFriend(const User* newFriend) 
{ 
    // check that newFriend is valid and is not already a friend 
    if (newFriend == NULL || isFriend(newFriend)) return FAILURE; 
    friends_.push_back(newFriend); 
    friendsNum_++; 
    return SUCCESS; 
} 

при компиляции файла .c я получаю ошибку компиляции:

invalid conversion from 'const User*' to 
std::vector User*::value_type 
  1. Почему мы получаем эту ошибку, если push_back обещает не изменение val?

  2. Каков правильный и чистый способ преодоления ошибки? возможно, const_cast?

спасибо!

user.h:

class User { 
... 
public: 
    vector<User*> friends_; 
... 
} 
+0

Можете ли вы показать больше кода? В частности, какой тип «друзей»? – sfjac

+0

Вы сохраняете вектор указателей ...? – Rufflewind

+0

Rufflewind: yes –

ответ

5

Существует логическая проблема с вашим кодом. А именно, вы сохраняете указатели на изменяемые объекты:

vector<User*> friends_; 

И все же ваш метод addFriend() принимает указатель на константный объект:

Result User::addFriend(const User* newFriend) 
//      ^^^^^ 
{ 
    // stuff.. 
    friends_.push_back(newFriend); 
} 

Те не выстраиваются в линию. Как есть, push_back должен будет преобразовать const User* в User*, отсюда и ошибка компиляции. Один или другой из этих типов должен быть изменен. Либо friends_ должен быть vector<const User*> (если вы действительно не намереваетесь модифицировать эти объекты) или addFriend необходимо принять User* (если имеется). Не используйте const_cast!

+0

, если я объявляю вектор, как вы предложили: vector , это означает, что указатели в векторе являются const или объектом, на которые указывают? –

+1

@Day_Dreamer 'const Пользователь *' является указателем на 'const User', объект, на который указывает' const'. Другой способ, 'User * const', был бы указателем' const' для изменяемого 'User' ... который вы не можете иметь' vector' of. – Barry

+0

большое спасибо! –

6

Вы хранения вектора указателей:

std::vector<User*> friends_; 

Там проблема с этим подходом, однако. Обратите внимание, что эти указатели не являются const User*: любой, у кого есть доступ friends_, должен иметь право изменять User.

Тип параметра в vector здесь User*, а не User, что означает value_type ≡ User.Таким образом, эта линия

void push_back (const value_type& val); 

следует интерпретировать следующим образом:

void push_back (const User*& val); 

Обратите внимание, что the syntax is a bit misleading here; более ясный способ смотреть на это так:

void push_back (User *const &val); 

const изменяет то, что находится на левой стороне: предотвращает указатель от изменений, но это не делает ничего, чтобы предотвратить саму, лежащую в основе User от изменения ,

Из-за const влияет только на указатель, но не User, переходящая в const User* нарушило бы контракт:

Result User::addFriend(const User* newFriend){ 
    … 
    friends_.push_back(newFriend); 
    … 
} 

Вы не можете это сделать. Поскольку addFriend обещает не допустить изменения User, хранение его в векторе неконстантноUser* позволит любому, у кого есть доступ к вектору, для изменения User, однако, пожалуйста.

Возможные решения:

  • Пусть addFriend взять User* вместо const User*. Еще лучше: используйте ссылку, если у вас нет повода для этого.
  • Изменить friends_ Использовать const User* вместо User*. Еще лучше: сохраните User s напрямую, а не как указатели.
  • Сделайте копию User.
0

Я думаю, что я понял это благодаря Collin Dauphinee. Невозможно добавить пользователя * к вектору non const User *.

декларация должна быть обновлена ​​в файле .h:

class User{ 
... 
public: 
    vector<const User*> friends_; 
... 
} 
0

это рекомендуется использовать совместно PTR или uniquer PTR для friends_ члена. Так лучше практика, чтобы объявить friends_ (если друзья будут разделены) быть:

typedef std::shared_ptr<User> sharedUsers; 
std::vector< sharedUsers> friends_ 

или если ваши друзья не будут разделены:

typedef std::unique_ptr<User> sharedUsers; 
std::vector<sharedUsers> friends_ 

этим способом все управление памятью будет быть делегированы вашим умным указателям.

0

Путаница возникает из-за подписью:

void push_back (const value_type& val); 

не приводит к этому (при инстанцировании вектор с User*).

void push_back (const User * & val); //wrong. but visually looks same! 

Скорее всего, это приводит к

void push_back (User * const & val); //right. but visually looks different 

Теперь становится немного яснее, почему объект типа const User* не может быть передан в эту функцию, так как:

  • const User * означает объект Указанный указателем является const. Сам указатель не является константой.

  • тогда как User *const означает, что объект, на который указывает указатель, не является константой. Это сам указатель, который является константой.

Обратите внимание, что const User* и User const* означают одно и то же вещь.

Это одна из причин, почему я предпочитаю писать const после имени типа в шаблонах. Если программисты делают эту привычку, то push_back функция будет выглядеть следующим образом:

void push_back(value_type const & val); 

который при инстанцировании с User*, могут быть легко переведены нами, программистов, в этом:

void push_back(User * const & val); //right. visually similar as well. 

что именно то, что должен быть.

Надеюсь, что это поможет.

Смежные вопросы