2016-01-06 8 views
2

g++ -std=c++11 не скомпилирует класс, содержащий контейнер, содержащий уникальные указатели, указывающие на объявленный вперед класс. Вопросы:C++ 11 контейнер unique_ptr объявленного переднего класса

  • Почему?
  • Есть ли разумное решение?

Пример кода:

#include <vector> 
#include <memory> 

// variant 1 (with full class definition): compiles 
class Bar { [..] }; 
using BarPtr = std::unique_ptr<Bar>; 

// variant 2 (with shared instead of unique pointers): compiles 
using BarPtr = std::shared_ptr<class Bar>; 

// variant 0 (which is what we want): compilation fails below 
using BarPtr = std::unique_ptr<class Bar>; 

// end of variants 

class Foo { 
    std::vector<BarPtr> vec; 
public: 
    Foo() {} // compilation of variant 0 fails here: 
      // In instantiation of ‘void std::default_delete<Bar>::operator()(Bar*) const 
      // ... 
      // invalid application of ‘sizeof’ to incomplete type ‘Bar’ 
}; 

Я видел How to forward declare a class to be used in a standard container of unique_ptr и Is std::unique_ptr<T> required to know the full definition of T?, но не найти убедительные ответы на мои вопросы выше.

ответ

0

Вы можете сделать это:

#include <vector> 
#include <memory> 

class Bar; 
using BarPtr = std::unique_ptr<Bar>; 

class Foo { 
    std::vector<BarPtr> vec; 
public: 
    Foo() {} // variant 3 fails here: 
      // invalid application of ‘sizeof’ to incomplete type ‘Bar’ 
}; 


//Implementation goes here 
class Bar{}; 
int main(){ 
    Foo a; 
} 

Live Demo

+0

Я подтверждаю, что это скомпилировано под g ++. Программа 'main' не нужна. Однако реализация 'class Bar {[...]};' is. Таким образом, порядок в исходном файле не имеет значения. Тем не менее, я хочу реализовать класс 'Bar' в другом компиляторе. –

+0

Да, главное, чтобы убедиться, что все в порядке. Если вы хотите перейти к объявлению вперед, вам нужно, наконец, реализовать класс где-то, чтобы не получить проблему с связыванием или, возможно, в вашей ошибке компиляции из-за отсутствия deleter (deconstructor) –

0

Проблема заключается в том, что вы не можете удалить с помощью указателя на незавершенных (вперед объявившего) типа. Убедитесь, что определение Bar отображается в деструкторе содержащего класса или использует пользовательский удаляющий файл для unique_ptr, который его видит. Смотрите также std::unique_ptr with an incomplete type won't compile

+0

Ошибка компиляции в * конструкторе * 'Foo() '; добавление деструктора '~ Foo()' не помогает. –

0

сообщение об ошибке в строке

Foo() {}; 

, кажется, сказать, что деструктор ~Bar() требуется. Но почему? Эта часть моего вопроса все еще открыта.

Что касается практического решения, однако, ответ прост: Замените эту строку на

Foo(); 

и осуществлять Foo::Foo в модуле компиляции, который видит полное определение класса Bar.

+0

как это отличается от моего ответа? –

+0

и имейте в виду, что если вы не реализовали конструктор, по умолчанию он будет реализован автоматически. –

+0

Насколько мне известно, * Объявление * конструктора предотвратит автоматическую * реализацию * по умолчанию. –

1

Вам необходимо переместить те части Foo в файл реализации, которым необходимо полное определение бара (см. Таблицу Howard Hinnant: https://stackoverflow.com/a/6089065/2173029). Следуя этому руководству, это составляет:

#include <vector> 
#include <memory> 

class Bar; 
using BarPtr = std::unique_ptr<Bar>; 

class Foo { 
    std::vector<BarPtr> vec; 
public: 
    Foo(); // Needs Bar in implementation 
    ~Foo();// Needs Bar in implementation 
};