Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
671 views
in Technique[技术] by (71.8m points)

c++ - std::unique_ptr and custom deleters

Scott Meyer’s “Effective Modern C++” discusses the use of std::unique_ptr with custom deleter and states:

Deleters that are function pointers generally cause the size of a std::unique_ptr to grow from one word to two. For deleters that are function objects, the change in size depends on how much state is stored in the function object. Stateless function objects (e.g., from lambda expressions with no captures) incur no size penalty, and this means that when a custom deleter can be implemented as either a function or a captureless lambda expression, the lambda is preferable.

As an example, this:

auto delInvmt1 = [](Investment* pInvestment) {
makeLogEntry(pInvestment);
delete pInvestment;
};

template<typename... Ts>
std::unique_ptr<Investment, decltype(delInvmt1)>
makeInvestment(Ts&&... args);

is better than this:

void delInvmt2(Investment* pInvestment) {
    makeLogEntry(pInvestment);
    delete pInvestment;
}

template<typename... Ts>
std::unique_ptr<Investment, void (*)(Investment*)>
makeInvestment(Ts&&... params);

I can see that in the second case a pointer to the deleter function needs to be stored in the unique_ptr, but why does nothing similar need to be stored for the lambda case?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As @milleniumbug said, std::unique_ptr use Empty Base Optimization. It means you can declare a class with no data member:

class empty
{
public:
   // methods
};

If you have another class that declare a member variable of empty inside it, the size of your class will increase even if empty has no data member:

class foo
{
public:
    int i;
    empty em;
};

In this case size of foo will be 8 byte. But if you declare foo to inherit from empty, this inheritance has no effect in size of foo and it's size will be 4 byte:

class foo : public empty 
{
public:
    int i;
};

If you take a look into std::unique_ptr implementation of your compiler you will see this. I'm using VC++ 2015 and in this compiler structure of std::unique_ptr is like below:

template<class _Ty, class _Dx>  // = default_delete<_Ty>
class unique_ptr : public _Unique_ptr_base<_Ty, _Dx>

It inherit from this class:

template<class _Ty, class _Dx>
class _Unique_ptr_base
{   // stores pointer and deleter
 public:
 ...
 _Compressed_pair<_Dx, pointer> _Mypair;
};

In _Unique_ptr_base there is a member of type _Compressed_pair. This class is declared in this way:

template<class _Ty1, class _Ty2, bool = is_empty<_Ty1>::value && !is_final<_Ty1>::value>
class _Compressed_pair final
    : private _Ty1

{   // store a pair of values, deriving from empty first
private:
     _Ty2 _Myval2;

Actually this class is specialized if it's second template argument is an empty class. In this case it inherit from empty deleter class and declare a member variable of first template argument that is std::unique_ptr pointer.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...