Pimpl idiom using shared_ptr working with incomplete types

I read Scott Meyers' Effective Modern C ++ and discusses the use of the pimpl idiom and points to the implementation class with unique_ptr, but there is a problem of special member functions (such as destructors) requiring a type to be complete. This is because the unique_ptrdefault default statically states whether the type to be deleted will be completed delete p. Thus, any special member functions of the class must be defined in the implementation file (and not in the compiler) after the implementation class is defined.

At the end of the chapter, he mentions that there is no need to define special member functions in the implementation file if the smart pointer is used shared_ptr, and this is due to the way it supports the custom div. Quote:

The difference in behavior between std :: unique_ptr and std :: shared_ptr for pImpl pointers stems from the different ways that these smart pointers support user-deleted ones. For std :: unique_ptr, the deleter type is part of the smart pointer type, and this allows compilers to generate less structure runtime data and faster runtime code. The consequence of this greater efficiency is that the indicated types must be complete when special functions are generated by the compiler (for example, destructors or move operations). For std :: shared_ptr, the deleteter type is not part of the smart pointer type. This requires longer execution time of the data structure and somewhat slower code, but pointer types do not have to be complete when special functions are used,generated by the compiler.

Despite this, I still do not understand why it shared_ptrcan work without completing the class. It seems that the only reason for the lack of a compiler error during use shared_ptris that there is no static type statement unique_ptr, and that undefined runtime behavior can occur due to this lack of statement.

I do not know the implementation of the destructor shared_ptr, but (from reading C ++ Primer) I gathered the impression that it works something like this:

del ? del(p) : delete p;

Where delis the pointer or function object for the user deleter. Cppreference also allows you to clear the destructor shared_ptrwithout using custom deletiondelete p

3) delete delete ptr, T ;.... Y . delete , .

, . pimpl:

//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;
}

Widget a main.cpp shared_ptr Widget ( main.cpp), shared_ptr delete pImpl, . Impl , delete pImpl. , , undefined?

, , idiom pimpl shared_ptr - , undefined?

+4
1

:

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

std::funciton<void(Impl*)>.

shared_ptr T*, std::function. .

, , Impl, , , pImpl T*.

+6

Source: https://habr.com/ru/post/1660858/


All Articles