Почему я получаю ошибку при вызове front () в boost::ptr_list?

#c

#c

Вопрос:

У меня есть виртуальный класс basic_action . Класс sippeers наследует class basic_action . Для хранения экземпляров sippeers классов, которые я использую boost::ptr_list . Вот пример кода:

 boost::ptr_list<basic_action> ActionsList;
sippeers spclass;
ActionsList.push_back(amp;spclass);
basic_action *sp = ActionsList.front();
  

Здесь я создаю экземпляр prt_list с указателями на экземпляры моих basic_action классов.
Затем я создаю новый экземпляр моего sippeers класса.
Затем я вставляю указатель на sippeers класс в ptr_list .

Последняя строка завершается ошибкой.

Не удается преобразовать ‘basic_action’ в ‘basic_action *’.

Но basic_action * внутри есть, а не basic_action !

Комментарии:

1. Это не имеет отношения к вашему вопросу, но контейнеры с указателями boost становятся владельцами объектов, которые вы в них помещаете. Вы не хотите помещать объект, выделенный стеком, в ptr_list.

Ответ №1:

boost::ptr_list::front() возвращает ссылку на шаблонный тип, а не указатель.

Итак, в этом случае он возвращает basic_actionamp; .

Смотрите документацию здесь для ptr_sequence_adapter , из которой ptr_list является производным.

Итак, ваш код должен гласить:

 boost::ptr_list<basic_action> ActionsList;
sippeers spclass;
ActionsList.push_back(amp;spclass);
basic_action amp;sp = ActionsList.front();
  

Комментарии:

1. boost::ptr_list::front() возвращает ссылку. Последняя строка должна быть: basic_actionamp; sp = ActionsList.front();

2. @Ferruccio Спасибо — поймал мою опечатку и отредактировал около 7 минут назад. 🙂

Ответ №2:

ptr_list::front() возвращает ссылку на первый объект в списке. Если бы basic_action был конкретным типом, вы могли бы выполнить оба следующих действия.

 // 1
basic_actionamp; sp = ActionsList.front();

// 2
basic_action sp = ActionsList.front();
  

# 1 сделал бы sp ссылкой на первый объект в списке. Другими словами, любые изменения, внесенные вами через sp, также изменят первый объект в списке.

# 2 создаст экземпляр нового объекта basic_action и скопирует содержимое первого объекта в списке в этот новый объект. Любые изменения в нем не повлияют на первый элемент в списке.

Если basic_action является абстрактным классом, опция # 2 вам больше недоступна, потому что вы не можете создавать экземпляры объектов абстрактного класса.

кроме того, вы не должны помещать объекты, выделенные стеком, в контейнер указателя boost. Плохие вещи произойдут, когда ptr_list выйдет за пределы области видимости и попытается удалить все содержащиеся в нем объекты. Вместо этого сделайте что-то вроде:

 boost::ptr_list<basic_action> ActionsList;
ActionsList.push_back(new sippeers);
basic_actionamp; sp = ActionsList.front();
  

Ответ №3:

Если вы посмотрите на заголовок, то увидите, что:

 template
<
    class T,
    class VoidPtrSeq,
    class CloneAllocator = heap_clone_allocator
>
class ptr_sequence_adapter
{
public: // construct/copy/destroy
    template< class InputIterator >
    assign( InputIterator first, InputIterator last );
    template< class InputRange >
    assign( const InputRangeamp; e );

public: // element access
    Tamp;        front();
  

(Примечание; ptr_list напрямую наследуется от ptr_sequence_adapter) Итак, вы получаете тип, а не ссылку на тип; он выполняет автоматическое разыменование для вас:

 basic_action sp = ActionsList.front();
  

правильно.

Комментарии:

1. Я пытался использовать этот код, но Visual Studio выдает ошибку: ошибка C2259: ‘basic_action’: не удается создать экземпляр абстрактного класса.

2. @CagoBHuK: это потому, что это неверно. Вам повезло, что вы получаете еще одну ошибку компилятора, а не странное поведение из-за непреднамеренного нарезания.

3. @CagoBHuK: проблема в том, что boost::ptr_list::front() возвращает ссылку. Вы можете назначить его ссылке (basic_action amp; sp = …), но без ссылки он попытается скопировать объект, на который ссылается, в новый объект basic_action (который он не может создать, потому что это абстрактный тип)