c++ ++> make - Является ли std :: unique_ptr <T> необходимым для определения полного определения T?





3 Answers

Компилятор нуждается в определении Thing для создания деструктора по умолчанию для MyClass. Если вы явно объявляете деструктор и перемещаете его (пустую) реализацию в файл CPP, код должен компилироваться.

shared_ptr ::< make_shared

У меня есть код в заголовке, который выглядит так:

#include <memory>

class Thing;

class MyClass
{
    std::unique_ptr< Thing > my_thing;
};

Если я включу этот заголовок в cpp, который не включает определение типа Thing , то это не компилируется под VS2010-SP1:

1> C: \ Program Files (x86) \ Microsoft Visual Studio 10.0 \ VC \ include \ memory (2067): ошибка C2027: использование неопределенного типа 'Thing'

Замените std::unique_ptr на std::shared_ptr и он скомпилируется.

Итак, я предполагаю, что это текущая реализация VS2010 std::unique_ptr unique_ptr, которая требует полного определения и полностью зависит от реализации.

Либо это? Есть ли что-то в его стандартных требованиях, что делает невозможным реализацию проекта std::unique_ptr только для прямого объявления? Это странно, поскольку он должен держать указатель на Thing , не так ли?




Похоже, что текущие ответы не совсем сбивают с толку, почему конструктор по умолчанию (или деструктор) является проблемой, но пустые, объявленные в cpp, не являются.

Вот что происходит:

Если внешний класс (т.е. MyClass) не имеет конструктора или деструктора, тогда компилятор генерирует значения по умолчанию. Проблема заключается в том, что компилятор по существу вставляет пустой конструктор / деструктор по умолчанию в файл .hpp. Это означает, что код для contructor / destructor по умолчанию компилируется вместе с двоичным исполняемым файлом исполняемого файла, а не двоичными файлами вашей библиотеки. Однако эти определения не могут действительно построить частичные классы. Поэтому, когда компоновщик входит в двоичный файл библиотеки и пытается получить конструктор / деструктор, он не находит и вы получаете ошибку. Если код конструктора / деструктора был в вашем .cpp, то в бинарнике библиотеки есть доступное для ссылки.

Таким образом, это не связано с использованием unique_ptr вместо shared_ptr для сценария выше, если вы используете современные компиляторы (старый компилятор VC ++ может иметь ошибку в реализации unique_ptr, но VC ++ 2015 отлично работает на моей машине).

Итак, мораль этой истории состоит в том, что ваш заголовок должен оставаться свободным от определения конструктора / деструктора. Он может содержать только их декларацию. Например, ~MyClass()=default; в hpp не будет работать. Если вы разрешите компилятору вставлять конструктор по умолчанию или деструктор, вы получите ошибку компоновщика.

Еще одна сторона примечания. Если вы все еще получаете эту ошибку даже после того, как у вас есть конструктор и деструктор в файле cpp, скорее всего, причина в том, что ваша библиотека не скомпилирована должным образом. Например, однажды я просто изменил тип проекта из Консоли в библиотеку в VC ++, и я получил эту ошибку, потому что VC ++ не добавил символ препроцессора _LIB и создал то же самое сообщение об ошибке.




Просто для полноты:

Заголовок: Ах

class B; // forward declaration

class A
{
    std::unique_ptr<B> ptr_;  // ok!  
public:
    A();
    ~A();
    // ...
};

Источник A.cpp:

class B {  ...  }; // class definition

A::A() { ... }
A::~A() { ... }

Определение класса B должно рассматриваться конструктором, деструктором и всем, что могло бы неявно удалить B. (Хотя конструктор не отображается в списке выше, в VS2017 даже конструктору необходимо определение B. И это имеет смысл при рассмотрении что в случае исключения в конструкторе unique_ptr снова уничтожается.)




Related