Как мне использовать unique_ptr для pimpl? - PullRequest
60 голосов
/ 26 января 2012

Вот упрощение того, что я вижу, когда пытаюсь использовать unique_ptr для pimpl.Я выбрал unique_ptr, потому что действительно хочу, чтобы класс владел указателем - я хочу, чтобы время жизни указателя pimpl и класса было одинаковым.

В любом случае, вот заголовок:

#ifndef HELP
#define HELP 1

#include <memory>

class Help
{

public:

  Help(int ii);
  ~Help() = default;

private:

  class Impl;
  std::unique_ptr<Impl> _M_impl;
};

#endif // HELP

Вот источник:

#include "Help.h"

class Help::Impl
{
public:
  Impl(int ii)
  : _M_i{ii}
  { }

private:

  int _M_i;
};

Help::Help(int ii)
: _M_impl{new Help::Impl{ii}}
{ }

Я мог бы прекрасно скомпилировать их в библиотеку.Но когда я пытаюсь использовать его в тестовой программе, я получаю

ed@bad-horse:~/ext_distribution$ ../bin/bin/g++ -std=c++0x -o test_help test_help.cpp Help.cpp
In file included from /home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/memory:86:0,
                 from Help.h:4,
                 from test_help.cpp:3:
/home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = Help::Impl]':
/home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/unique_ptr.h:245:4:   required from 'void std::unique_ptr<_Tp, _Dp>::reset(std::unique_ptr<_Tp, _Dp>::pointer) [with _Tp = Help::Impl; _Dp = std::default_delete<Help::Impl>; std::unique_ptr<_Tp, _Dp>::pointer = Help::Impl*]'
/home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/unique_ptr.h:169:32:   required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = Help::Impl; _Dp = std::default_delete<Help::Impl>]'
Help.h:6:7:   required from here
/home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/unique_ptr.h:63:14: error: invalid application of 'sizeof' to incomplete type 'Help::Impl'

Это хорошо известная функция безопасности .Я пытался следовать.

Моя проблема в том, что если бы я поместил объявление Help :: Impl в заголовок, это, казалось бы, исключило бы любое преимущество pimpl.Макет класса виден пользователям.Определение скрыто, но я мог бы сделать это с помощью класса Help и закрытых членов.Кроме того, включение объявления Impl приводит к появлению новых заголовков, которые я бы хотел оставить отдельно.

Чего мне не хватает?Что люди ставят в декларации Impl и где?Я делаю справку дтор неправильно?Argh!

Ответы [ 2 ]

79 голосов
/ 26 января 2012

Я считаю, что ваш test_help.cpp действительно видит деструктор ~Help(), который вы объявили по умолчанию.В этом деструкторе компилятор также пытается сгенерировать деструктор unique_ptr, но для этого ему нужно объявление Impl.

Так что, если вы переместите определение деструктора в Help.cpp, эта проблема должнауйти.

- РЕДАКТИРОВАТЬ - Вы можете определить деструктор, который будет использоваться по умолчанию в файле cpp:

Help::~Help() = default;
8 голосов
/ 09 марта 2018

Обратите внимание на это из unique_ptr определение:

std :: unique_ptr может быть создано для неполного типа T, например, для облегчения использования в качестве дескриптора в идиоме pImpl,Если используется средство удаления по умолчанию, T должен быть завершен в той точке кода, где вызывается средство удаления, что происходит в деструкторе, операторе присваивания перемещения и сбрасывает функцию-член std :: unique_ptr.

...