本文介绍了使用shared_ptr处理不完整类型的Pimpl习惯用法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读Scott Meyers的《 Effective Modern C ++》,他正在讨论pimpl习惯用法,并使用unique_ptr指向实现类,但是存在一个特殊的成员函数(例如析构函数)要求该类型的问题完整.这是因为unique_ptr的默认删除程序会在使用delete p之前静态断言要删除的类型是否完整.因此,必须在实现文件中定义类的任何特殊成员函数(而不是由编译器生成),而在实现类定义后 .

I'm reading Effective Modern C++ by Scott Meyers and he's discussing the use of the pimpl idiom and pointing to the implementation class with unique_ptr, but there is an issue of special member functions (such as destructors) requiring the type to be complete. This is because unique_ptr's default deleter statically asserts whether the type to be deleted is complete, before delete p is used. So any special member functions of the class must be defined in the implementation file (rather than being compiler-generated), after the implementation class has been defined.

在本章的最后,他提到,如果使用的智能指针为shared_ptr,则无需在实现文件中定义特殊的成员函数,这源于它支持自定义删除器的方式.引用:

At the end of the chapter, he mentions there is no need to define special member functions in the implementation file if the smart pointer used is shared_ptr, and this stems from the way it supports a custom deleter. To quote:

尽管如此,我仍然看不到为什么shared_ptr在类未完成的情况下仍然可以工作.似乎使用shared_ptr时没有编译器错误的唯一原因是因为没有像unique_ptr那样的静态断言,并且由于缺少断言而可能发生未定义的运行时行为.

Despite this, I still can't see why shared_ptr could still work without the class being complete. It seems like the only reason there is no compiler error when using shared_ptr is because there is no static assertion like unique_ptr had, and that undefined runtime behaviour could instead occur because of this lack of assertion.

我不知道shared_ptr的析构函数的实现,但是(通过阅读C ++ Primer)我得到的印象是它的工作原理类似于:

I don't know the implementation of the shared_ptr's destructor, but (from reading C++ Primer) I gathered the impression it works something like:

del ? del(p) : delete p;

del是自定义删除器的指针或函数对象. Cppreference 还可以清除shared_ptr析构函数,而无需自定义删除器使用delete p

Where del is a pointer or function object to the custom deleter. Cppreference also makes it clear the shared_ptr destructor with no custom deleter uses delete p

重点强调已删除的类型必须完整的事实. pimpl惯用语的一个最小示例:

Emphasis on the fact that the deleted type must be complete. A minimal example of the pimpl idiom:

//widget.h

#ifndef WIDGET
#define WIDGET

#include <memory>

class Widget{
public:
    Widget();
private:
    struct Impl;
    std::shared_ptr<Impl> pImpl;

};

#endif // WIDGET

//widget.cpp

#include <string>
#include "Widget.h"

struct Widget::Impl{
    std::string name;
};

Widget::Widget(): pImpl(new Impl) {}

//main.cpp

#include <iostream>
#include "Widget.h"

int main(){
    Widget a;
}

编译main.cpp中的Widget a时,将为Widget类型(在main.cpp之内)实例化shared_ptr的模板,并且可能为shared_ptr生成的已编译析构函数包含行,因为我没有提供自定义删除器.但是,此时仍未定义Impl,但仍执行了行delete pImpl.当然,这是不确定的行为吗?

When Widget a in main.cpp is compiled, the template of shared_ptr is instantited for type Widget (within main.cpp) and presumably the resulting compiled destructor for shared_ptr contains execution of the line delete pImpl, because I have not supplied a custom deletor. However at that point, Impl still has not been defined, yet the line delete pImpl is executed. This, surely, is undefined behaviour?

那么在与shared_ptr一起使用pimpl习惯用法时,我不必在实现文件中定义特殊的成员函数来避免未定义的行为呢?

So how is it that when using the pimpl idiom with shared_ptr, I don't have to define the special member functions in the implementation file to avoid undefined behaviour?

推荐答案

在此处创建共享指针的删除器:

The deleter for a shared pointer is created here:

Widget::Widget(): pImpl(new Impl) {}

直到这一点,所有共享指针都具有与std::funciton<void(Impl*)>相同的作用.

until that point, all the shared pointer has is the equivalent of a std::funciton<void(Impl*)>.

当使用T*构造shared_ptr时,它将编写一个删除程序并将其存储在等效的std::function中.那时类型必须是完整的.

When you construct a shared_ptr with a T*, it writes a deleter and stores it in the std::function equivalent. At that point the type must be complete.

因此,在完全定义了Impl之后,您需要定义的唯一函数是从某种T*创建pImpl的那些函数.

So the only functions you have to define after Impl is fully defined are those that create a pImpl from a T* of some kind.

这篇关于使用shared_ptr处理不完整类型的Pimpl习惯用法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 09:10