C++11 контейнер unique_ptr для заранее объявленного класса
g++ -std=c++11
не компилирует класс, который содержит контейнер, содержащий уникальные указатели, которые указывают на объявленный вперед класс. Вопросы:
- Зачем?
- Есть ли разумное решение?
Пример кода:
#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’
};
Я видел, как переслать объявление класса для использования в стандартном контейнере unique_ptr и требуется ли std::unique_ptr
4 ответа
Вам нужно переместить те части Foo в файл реализации, для которых необходимо полное определение Bar (см. Таблицу Говарда Хиннанта: /questions/22207241/trebuetsya-li-stduniqueptrt-znat-polnoe-opredelenie-t/22207259#22207259). Следуя этому руководству, компилируется:
#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
};
Сообщение об ошибке в строке
Foo() {};
кажется, говорит, что деструктор ~Bar()
необходимо. Но почему? Эта часть моего вопроса все еще открыта.
Что касается практического решения, однако, ответ прост: замените вышеуказанную строку на
Foo();
и реализовать Foo::Foo
в модуле компиляции, который видит полное определение класса Bar
,
Вы можете сделать это:
#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;
}
Проблема в том, что вы не можете удалить указатель на неполный (объявленный в будущем) тип. Убедитесь, что определение Bar
отображается в деструкторе содержащего класса, или используйте пользовательское средство удаления для unique_ptr
это видит. Смотрите также std::unique_ptr с неполным типом не будет компилироваться