2016-02-12 5 views
0

Я пытаюсь изучить технику пимпла для C++. После того, как прошел через несколько статей в Интернете, я нашел, что есть два различных способа для Pimpl, одинПреимущество и недостаток использования указателя void в C++ pimpl

class X 
{ 
    public: 
    X(...parameters...) 
    ~X() 
    private: 
    struct Impl; 
    Impl* impl_; 
}; 

Другой способ заключается в использовании сырой пустой указатель, как

class X 
{ 
    public: 
    X(...parameters...) 
    ~X() 
    private: 
    void * impl_; 
}; 

Затем использовать static_cast, чтобы бросить указатель void возвращается к исходному типу.

Каковы преимущества и недостатки, сравнивающие эти два способа?

Спасибо!

+2

первый всегда лучше, так как он сохраняет информацию о типе –

+1

Нет смысла использовать указатель на пустоту, только недостатки. Если вы хотите скрыть объявление класса реализации, вместо этого используйте форвардное объявление; что позволит компилятору знать, что класс существует (чтобы вы не получали синтаксическую ошибку), сохраняя при этом все детали, скрытые внутри файла .cpp. –

ответ

6

Не используйте void* для реализации пикника или для большей части чего-либо в этом отношении. Он не дает никаких преимуществ; и имеет потенциальную проблему, если по какой-либо причине вы, если вы ошиблись static_cast, у вас будет неопределенное поведение.

Легко переадресовать свой класс реализации, как в первом примере. Это правильный способ реализации pimpl.

1

С помощью первого, используя отладчик, вы сможете просмотреть указатель impl и его значения данных. Если у вас есть указатель void*, вы не сможете этого сделать. Второй вариант не дает никаких преимуществ, о которых я знаю.

В любом случае, если у вас есть

Impl* GetImpl() { return impl_; } 

или

Impl* GetImpl() { return static_cast<Impl*>(impl_); } 

Обе функции будут генерировать точно такой же код сборки.

Если вам не нужен геттер, вы можете использовать его как: struct Impl* impl_;.

+0

@ M.M или c-style cast? –

+0

@AlexeyAndronov, который был бы действительным, хотя, как правило, рекомендуется использовать «наименее сильный» приказ, который выполняет эту работу, чтобы уменьшить вероятность случайного каста на неправильный тип, минуя ошибки компилятора –

+0

@MM, no, I означает, какой код будет генерировать компилятор? Я сомневаюсь, что он будет использовать кувалду 'reinterpret_cast' в качестве первого выбора. –