使用std :: unique_ptr的C ++ Pimpl成语不完整类型 [英] C++ Pimpl Idiom Incomplete Type using std::unique_ptr

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

问题描述

对于为演示此问题所需的大量代码,我深表歉意.我在使用stmpl :: unique_ptr的pimpl惯用语时遇到问题.具体地说,当将一个类(具有pimpl实现的)用作另一个具有pimpl'ed实现的复合类的成员数据时,似乎会出现此问题.

I apologize for the large amount of code required to demonstrate the issue. I am having a problem using the pimpl idiom with std::unique_ptr. Specifically the problem seems to occur when one class (which has pimpl'ed implementation) is used as member data in another composite class with pimpl'ed implementation.

我能够找到的大多数答案都缺乏

Most of the answers I've been able to find deal with a lack of explicit destructor declaration, but as you can see here, I have declared and defined the destructors.

这段代码有什么问题,可以在不更改设计的情况下将其修改为可编译的代码吗?

注意:该错误似乎发生在SomeComposite :: getValue()的定义中,并且编译器只有在编译时才能看到该错误.在memory.h中遇到错误,并且消息是将'sizeof'的无效应用程序应用于不完整的类型'pimplproblem :: SomeInt :: impl'.

Note: the error seems to occur in the definition of SomeComposite::getValue() and that the compiler cannot see the error until compile time. The error is encountered in memory.h and the message is Invalid application of 'sizeof' to an incomplete type 'pimplproblem::SomeInt::impl'.

SomeInt.h

#pragma once
#include <iostream>
#include <memory>

namespace pimplproblem
{
    class SomeInt
    {

    public:
        explicit SomeInt( int value );
        SomeInt( const SomeInt& other ); // copy
        SomeInt( SomeInt&& other ) = default; // move
        virtual ~SomeInt();
        SomeInt& operator=( const SomeInt& other ); // assign
        SomeInt& operator=( SomeInt&& other ) = default; // move assign
        int getValue() const;

    private:
        class impl;
        std::unique_ptr<impl> myImpl;
    };
}

SomeInt.cpp

#include "SomeInt.h"

namespace pimplproblem
{
    class SomeInt::impl
    {
    public:
        impl( int value )
        :myValue( value )
        {}

        int getValue() const
        {
            return myValue;
        }
    private:
        int myValue;
    };

    SomeInt::SomeInt( int value )
    :myImpl( new impl( value ) )
    {}

    SomeInt::SomeInt( const SomeInt& other )
    :myImpl( new impl( other.getValue() ) )
    {}

    SomeInt::~SomeInt()
    {}

    SomeInt& SomeInt::operator=( const SomeInt& other )
    {
        myImpl = std::unique_ptr<impl>( new impl( other.getValue() ) );
        return *this;
    }

    int SomeInt::getValue() const
    {
        return myImpl->getValue();
    }
}

SomeComposite.h

#pragma once
#include <iostream>
#include <memory>
#include "SomeInt.h"

namespace pimplproblem
{
    class SomeComposite
    {   

    public:
        explicit SomeComposite( const SomeInt& value );
        SomeComposite( const SomeComposite& other ); // copy
        SomeComposite( SomeComposite&& other ) = default; // move
        virtual ~SomeComposite();
        SomeComposite& operator=( const SomeComposite& other ); // assign
        SomeComposite& operator=( SomeComposite&& other ) = default; // move assign
        SomeInt getValue() const;

    private:
        class impl;
        std::unique_ptr<impl> myImpl;
    };
}

SomeComposite.cpp

#include "SomeComposite.h"

namespace pimplproblem
{
    class SomeComposite::impl
    {
    public:
        impl( const SomeInt& value )
        :myValue( value )
        {}

        SomeInt getValue() const
        {
            return myValue;
        }
    private:
        SomeInt myValue;
    };

    SomeComposite::SomeComposite( const SomeInt& value )
    :myImpl( new impl( value ) )
    {}

    SomeComposite::SomeComposite( const SomeComposite& other )
    :myImpl( new impl( other.getValue() ) )
    {}

    SomeComposite::~SomeComposite()
    {}

    SomeComposite& SomeComposite::operator=( const SomeComposite& other )
    {
        myImpl = std::unique_ptr<impl>( new impl( other.getValue() ) );
        return *this;
    }

    SomeInt SomeComposite::getValue() const
    {
        return myImpl->getValue();
    }
} 

推荐答案

您不能将在头文件中声明的默认构造函数和赋值运算符(例如SomeInt( SomeInt&& other ) = default;)与Pimpl类一起使用,因为默认实现是内联的,并且在声明SomeInt的声明SomeInt::impl处不完整,因此unique_ptr抱怨.您必须自行声明和定义所有特殊成员函数(即在实现文件中).

You can't use defaulted constructors and assignment operators (such as SomeInt( SomeInt&& other ) = default;) declared in header file with Pimpl classes, because the default implementations are inline, and at the point of declaration SomeInt's declaration SomeInt::impl is incomplete, so unique_ptr complains. You have to declare and define out of line (that is, in implementation file) all special member functions yourself.

也就是说,如下更改SomeIntSomeComposite声明:

That is, change SomeInt and SomeComposite declarations as follows:

// SomeInt.h
SomeInt( SomeInt&& other ); // move
SomeInt& operator=( SomeInt&& other ); // move assign

// SomeInt.cpp
// after definition of SomeInt::impl
SomeInt::SomeInt( SomeInt&& other ) = default;
SomeInt& operator=( SomeInt&& other ) = default;

另一种选择是按照此答案中的建议创建自己的Pimpl指针.

Another option is to create your own Pimpl pointer, as suggested in this answer.

这篇关于使用std :: unique_ptr的C ++ Pimpl成语不完整类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆