使用std :: unique_ptr的C ++ Pimpl成语不完整类型 [英] C++ Pimpl Idiom Incomplete Type using std::unique_ptr
问题描述
对于为演示此问题所需的大量代码,我深表歉意.我在使用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.
也就是说,如下更改SomeInt
和SomeComposite
声明:
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屋!