C++ class destructor delete member if "owner"?
C++ class destructor delete member if "owner"?
我知道在 C++ 中,指针就是:指向内存位置的指针,没有 "owners" 的概念。但是考虑下面的情况(不一定是好的代码):
class A {
public:
A(){}
~A()
{ if(myObject!=nullptr)
delete myObject;
}
void createMember()
{myObject=new CrazyCustomClass();}
CrazyCustomClass *getMember()
{return myObject;}
private:
CrazyCustomClass *myObject=nullptr;
}
如果它有所作为,CrazyCustomClass 没有复制构造函数,因为复制它没有任何意义。非常简单 - 我有一个 class ,在实例化后的某个时候,可能会调用 new
来实例化 CrazyCustomClass *
类型的成员
问题是,如果在某个时候我创建了 class A
的副本(这很好 - 我希望能够复制 class A
)。当那个 copy 被删除时, original class 指向的对象也被删除了。例如:
void StupidFunction(A *firstObject){
//This is NOT a real function, it simply illustrates the effect of a third-party library function
//create a new object that is a copy of first object
A secondObject(*firstObject);
<do whatever with second object>
//secondObject goes out of scope here and gets deleted.
}
A *firstObject=new A();
firstObject->createMember();
stupidFunction(firstObject);
CrazyCustomClass *customObject=firstObject.getMember(); //this is now an invalid pointer
在上面的示例中,StupidFunction
来自第三方库,其想法是它提供了对象的 "temporary" 副本,您可以在不弄乱原始对象的情况下使用该副本对象,这很好。 Class A
和CrazyCustomClass
都是我的代码,可以随意更改。不幸的是,当 "temporary" 副本被删除时,我编写析构函数的方式导致了问题。
我的第一个想法是使用 shared_ptr,像这样:
std::shared_ptr<CrazyCustomClass> sharedObject=std::make_shared<CrazyCustomClass>(new CrazyCustomClass);
...但这在编译时给了我一个错误:
candidate constructor (the implicit copy constructor) not viable: no
known conversion from 'CrazyCustomClass *' to 'const CrazyCustomClass'
for 1st argument; dereference the argument with *
并且如果我 做 取消引用带有 * 的参数,它会给我一个关于 "CrazyCustomClass"
的复制构造函数被删除的错误,这是真的 - 没有复制 CrazyCustomClass
.
的明智方法
所以我的问题是:如何重构 class A
以便 myObject
在 firstObject
超出范围但 不 [=48] 时被正确删除=] 当 A 的任何 "temporary" 个副本被删除时?
使用 shared_ptr
实际上是解决这个问题的方法,但是在原始问题中尝试的代码是不正确的。有两种(至少)不同的方法来初始化 shared_ptr
(参考:https://msdn.microsoft.com/en-us/library/hh279669.aspx)。首先,您可以使用 new
作为构造函数参数:
shared_ptr<CrazyCustomClass> myObject(new CrazyCustomClass)
其次,这是通常首选的方法,您可以使用 make_shared 函数(正如在原始 post 中尝试的那样),它不接受 new
对象,而是要传递给对象构造函数的 参数 ,在本例中为空:
shared_ptr<CrazyCustomClass> myObject=make_shared<CrazyCustomClass>()
原始代码简单地混淆了这两个方法,因此出现了有关复制构造函数的错误:它试图用指向 CrazyCustomClass
对象的指针实例化一个新的 CrazyCustomClass
对象作为构造函数参数。
一旦使用 shared_ptr
,必须删除析构函数中的 delete
。
感谢@tkausl 和@alterigel 指出问题评论中的错误!
我知道在 C++ 中,指针就是:指向内存位置的指针,没有 "owners" 的概念。但是考虑下面的情况(不一定是好的代码):
class A {
public:
A(){}
~A()
{ if(myObject!=nullptr)
delete myObject;
}
void createMember()
{myObject=new CrazyCustomClass();}
CrazyCustomClass *getMember()
{return myObject;}
private:
CrazyCustomClass *myObject=nullptr;
}
如果它有所作为,CrazyCustomClass 没有复制构造函数,因为复制它没有任何意义。非常简单 - 我有一个 class ,在实例化后的某个时候,可能会调用 new
来实例化 CrazyCustomClass *
问题是,如果在某个时候我创建了 class A
的副本(这很好 - 我希望能够复制 class A
)。当那个 copy 被删除时, original class 指向的对象也被删除了。例如:
void StupidFunction(A *firstObject){
//This is NOT a real function, it simply illustrates the effect of a third-party library function
//create a new object that is a copy of first object
A secondObject(*firstObject);
<do whatever with second object>
//secondObject goes out of scope here and gets deleted.
}
A *firstObject=new A();
firstObject->createMember();
stupidFunction(firstObject);
CrazyCustomClass *customObject=firstObject.getMember(); //this is now an invalid pointer
在上面的示例中,StupidFunction
来自第三方库,其想法是它提供了对象的 "temporary" 副本,您可以在不弄乱原始对象的情况下使用该副本对象,这很好。 Class A
和CrazyCustomClass
都是我的代码,可以随意更改。不幸的是,当 "temporary" 副本被删除时,我编写析构函数的方式导致了问题。
我的第一个想法是使用 shared_ptr,像这样:
std::shared_ptr<CrazyCustomClass> sharedObject=std::make_shared<CrazyCustomClass>(new CrazyCustomClass);
...但这在编译时给了我一个错误:
candidate constructor (the implicit copy constructor) not viable: no known conversion from 'CrazyCustomClass *' to 'const CrazyCustomClass' for 1st argument; dereference the argument with *
并且如果我 做 取消引用带有 * 的参数,它会给我一个关于 "CrazyCustomClass"
的复制构造函数被删除的错误,这是真的 - 没有复制 CrazyCustomClass
.
所以我的问题是:如何重构 class A
以便 myObject
在 firstObject
超出范围但 不 [=48] 时被正确删除=] 当 A 的任何 "temporary" 个副本被删除时?
使用 shared_ptr
实际上是解决这个问题的方法,但是在原始问题中尝试的代码是不正确的。有两种(至少)不同的方法来初始化 shared_ptr
(参考:https://msdn.microsoft.com/en-us/library/hh279669.aspx)。首先,您可以使用 new
作为构造函数参数:
shared_ptr<CrazyCustomClass> myObject(new CrazyCustomClass)
其次,这是通常首选的方法,您可以使用 make_shared 函数(正如在原始 post 中尝试的那样),它不接受 new
对象,而是要传递给对象构造函数的 参数 ,在本例中为空:
shared_ptr<CrazyCustomClass> myObject=make_shared<CrazyCustomClass>()
原始代码简单地混淆了这两个方法,因此出现了有关复制构造函数的错误:它试图用指向 CrazyCustomClass
对象的指针实例化一个新的 CrazyCustomClass
对象作为构造函数参数。
一旦使用 shared_ptr
,必须删除析构函数中的 delete
。
感谢@tkausl 和@alterigel 指出问题评论中的错误!