C++ 使用智能指针复制构造函数
我有一个类,有一个C++ 使用智能指针复制构造函数,c++,templates,smart-pointers,copy-constructor,C++,Templates,Smart Pointers,Copy Constructor,我有一个类,有一个std::unique\u ptr作为类成员。我想知道如何正确定义复制构造函数,因为我收到了以下编译器错误消息:错误C2248:std::unique\u ptr::unique\u ptr:无法访问类“std::unique\u ptr”中声明的私有成员。我的课堂设计看起来像: template <typename T> class Foo{ public: Foo(){}; Foo( Bar<T> *, int
std::unique\u ptr
作为类成员。我想知道如何正确定义复制构造函数,因为我收到了以下编译器错误消息:错误C2248:std::unique\u ptr::unique\u ptr:无法访问类“std::unique\u ptr”中声明的私有成员。我的课堂设计看起来像:
template <typename T>
class Foo{
public:
Foo(){};
Foo( Bar<T> *, int );
Foo( const Foo<T> & );
~Foo(){};
void swap( Foo<T> & );
Foo<T> operator = ( Foo<T> );
private:
std::unique_ptr<Bar> m_ptrBar;
int m_Param1;
};
template < typename T >
Foo<T>::Foo( const Foo<T> & refFoo )
:m_ptrBar(refFoo.m_ptrBar),
m_Param1(refFoo.m_Param1)
{
// error here!
}
template < typename T >
void Foo<T>::swap( Foo<T> & refFoo ){
using std::swap;
swap(m_ptrBar, refFoo.m_ptrBar);
swap(m_Param1, refFoo.m_Param1);
}
template < typename T >
Foo<T> Foo<T>::operator = ( Foo<T> Elem ){
Elem.swap(*this);
return (*this);
}
模板
福班{
公众:
Foo(){};
Foo(Bar*,int);
富(常富&);
~Foo(){};
无效掉期(Foo&);
Foo运算符=(Foo);
私人:
std::唯一的\u ptr m\u ptrBar;
int m_Param1;
};
模板
Foo::Foo(const Foo和refFoo)
:m_ptrBar(refFoo.m_ptrBar),
m_参数1(参考foo.m_参数1)
{
//这里出错了!
}
模板
void Foo::swap(Foo和refFoo){
使用std::swap;
交换(m_ptrBar,refFoo.m_ptrBar);
交换(m_Param1,refFoo.m_Param1);
}
模板
Foo-Foo::operator=(Foo-Elem){
要素互换(*本);
返回(*本条);
}
假设目标是复制并构造唯一拥有的条形图
template < typename T >
Foo<T>::Foo( const Foo<T> & refFoo )
: m_ptrBar(refFoo.m_ptrBar ? new Bar(*refFoo.m_ptrBar) : nullptr),
m_Param1(refFoo.m_Param1)
{
}
模板
Foo::Foo(const Foo和refFoo)
:m_ptrBar(refFoo.m_ptrBar?新条(*refFoo.m_ptrBar):nullptr),
m_参数1(参考foo.m_参数1)
{
}
独特的ptr文档:
Stores a pointer to an owned object. The object is owned by no other unique_ptr.
The object is destroyed when the unique_ptr is destroyed.
您不能复制它,因为两个对象不能拥有它
尝试切换到std::shared\u ptr
编辑我应该指出,这将使两个对象都有指向同一对象的指针。如果要复制唯一拥有的对象,Cubbi的解决方案是正确的。可以为此创建一个新的克隆类型
下面是一个调用派生对象的正确复制构造函数(和析构函数)的克隆ptr
的基本示例。这是通过在创建clone\u ptr
时创建一个“type erasure”助手来完成的
其他的实现可以在互联网上找到
#include <memory>
namespace clone_ptr_detail
{
template <class T>
class clone_ptr_helper_base
{
public:
virtual ~clone_ptr_helper_base() {}
virtual T* clone(const T* source) const = 0;
virtual void destroy(const T* p) const = 0;
};
template <class T, class U>
class clone_ptr_helper: public clone_ptr_helper_base<T>
{
public:
virtual T* clone(const T* source) const
{
return new U(static_cast<const U&>(*source));
}
virtual void destroy(const T* p) const
{
delete static_cast<const U*>(p);
}
};
}
template <class T>
class clone_ptr
{
T* ptr;
std::shared_ptr<clone_ptr_detail::clone_ptr_helper_base<T>> ptr_helper;
public:
template <class U>
explicit clone_ptr(U* p): ptr(p), ptr_helper(new clone_ptr_detail::clone_ptr_helper<T, U>()) {}
clone_ptr(const clone_ptr& other): ptr(other.ptr_helper->clone(other.ptr)), ptr_helper(other.ptr_helper) {}
clone_ptr& operator=(clone_ptr rhv)
{
swap(rhv);
return *this;
}
~clone_ptr()
{
ptr_helper->destroy(ptr);
}
T* get() const { /*error checking here*/ return ptr; }
T& operator* () const { return *get(); }
T* operator-> () const { return get(); }
void swap(clone_ptr& other)
{
std::swap(ptr, other.ptr);
ptr_helper.swap(other.ptr_helper);
}
};
#包括
名称空间克隆\u ptr\u详细信息
{
模板
类clone\u ptr\u helper\u base
{
公众:
虚拟~clone\u ptr\u helper\u base(){}
虚拟T*克隆(常数T*源)常数=0;
虚空破坏(常数T*p)常数=0;
};
模板
类clone\u ptr\u helper:public clone\u ptr\u helper\u base
{
公众:
虚拟T*克隆(常量T*源)常量
{
返回新U(静态_转换(*源));
}
虚空破坏(常数T*p)常数
{
删除静态_-cast(p);
}
};
}
模板
类克隆\u ptr
{
T*ptr;
std::共享ptr ptr\u助手;
公众:
模板
显式克隆ptr(U*p):ptr(p),ptr_助手(新克隆ptr_细节::克隆ptr_助手()){}
clone_ptr(const clone_ptr&other):ptr(other.ptr_helper->clone(other.ptr)),ptr_helper(other.ptr_helper){}
clone_ptr&operator=(clone_ptr rhv)
{
互换(rhv);
归还*这个;
}
~clone_ptr()
{
ptr_helper->销毁(ptr);
}
T*get()常量{/*此处检查错误*/return ptr;}
T运算符*()常量{return*get();}
T*运算符->()常量{return get();}
无效交换(克隆ptr和其他)
{
标准::交换(ptr,other.ptr);
ptr_helper.swap(其他.ptr_helper);
}
};
请参阅用法示例:
(但也许你真的不需要复制你的对象,而应该探索移动语义的可能性。例如,你可以有一个向量
,只要你不使用复制内容的函数。)@Cubbi,谢谢。我现在有另一个问题。Bar
类实际上是一个抽象基类,因此我收到一条新的错误消息:错误C2259:“Bar”:无法实例化抽象类
,除了将抽象基类转换为简单基类之外,还有什么解决方案吗?@Tin:在这种情况下,您需要添加一个纯虚拟的克隆()
函数调用基类,在每个派生类中重写以使用new
创建副本。然后初始化器变成bar(foo.bar?foo.bar->clone():nullptr)
@Tin如果我现在有一个私有成员的类,C++FAQ调用@MikeSeymour@Cubbi:std::vector mvector代码>,并且要定义复制构造函数和赋值运算符,那么我需要逐个元素地复制调用“clone()”虚拟函数的元素,对吗?因为如果我遵循参数化列表中复制构造函数的传统实现,即MyCollection::mycollecyon(const refCol):myvector(refCol.myvector){}
,我会得到一个编译器错误。@Cubbi,如果现在我只想std::move
指针呢?我尝试了一些东西,比如muptrbar(std::move(refFoo.m\u ptrBar))
,但没有成功。有什么建议吗?@w00te,谢谢。还有一个问题。如果Bar类实际上是一个抽象基类呢?我收到一条新的错误消息:错误C2259:'Bar':无法实例化抽象类
。除了将抽象基类转换为简单基类之外,还有什么解决方案吗?Cubbi的解决方案创建了一个新的Bar对象,该对象将包含在新类中的unique_ptr中。若bar是抽象的,那个么它就不能工作——它必须创建一个适用派生类的新对象。您必须添加逻辑才能实现这一点。