我正在使用图书馆的课程。让它成为A,它有一个字符指针" token"
我的代码:
void someFunction()
{
A a;
cout<<a.token;
anotherFunction(a);
cout<<a.token; // line 4: now token became invalid [1]
}
void anotherFunction(A copyOfA);
{
// doing something
} // on exit destructor of copyofA will be called
[1]为什么它变得无效:A类如下:
class A
{
char *token;
public:
A()
{
token = GetRandomToken(); // GetRandomToken will return a 'new Char' array
}
~A()
{
if(token != NULL)
{
delete[] token; // it is A's responsibility to delete the memory it created
token = NULL;
}
}
};
调用copyOfA的析构函数anotherFunction
时token
中的被删除。因此在第4行,令牌无效,因为a.token和copyOfA.token都指向到同一地址。
在下列情况下,解决方案是什么:
案例1:class A
位于给定的库中:因此我无法对其进行修改。
案例2:如果我可以修改class A
:处理此问题的好方法是什么?
我知道,如果通过传递引用调用anotherFunction,我就不会遇到这个问题。但是,如果我必须在某个时刻保留对象的副本呢?
在此处查看示例代码:https://ideone.com/yZa4k4
答案 0 :(得分:3)
如果您无法修改class A
,则应避免复制它。我认为最安全的方法是动态分配class A
对象:
void anotherFunction(std::shared_ptr<A> aPtr)
{
// please also note that in your case token is PRIVATE
std::cout << aPtr->token << std::endl;
}
std::shared_ptr<A> aPtr(new A);
std::cout << aPtr->token << std::endl;
anotherFunction(aPtr);
或者,如果您坚持使用堆栈分配,则应将anotherFunction
签名更改为:
void anotherFunction(const A& a)
{
std::cout << a.token << std::endl;
}
通过const引用传递你的参数(避免复制构造函数)。
现在,如果您可以修改class A
,则应该应用the rule of three/five/zero,因为您有非平凡的析构函数。执行此操作的懒惰方法是将其他构造函数声明为已删除(然后,就像在您的示例中,您无法复制A
对象,但您也可以保证没有人会尝试这样做):
class A
{
public:
// for this example purpose I made token PUBLIC, but it is a bad idea in general
char *token;
A()
{
token = GetRandomToken(); // GetRandomToken will return a 'new Char' array
}
~A()
{
if(token != NULL)
{
delete[] token; // it is A's responsibility to delete the memory it created
token = NULL;
}
}
A(const A& other) = delete;
A(A&& other) = delete;
};
或者,如果你不懒,你实际上可以考虑如何将内存从一个对象中的token
指针复制到另一个对象 - 这取决于你如何实现它。这取决于GetRandomToken
的要求和实施。
答案 1 :(得分:-1)
如果您的示例准确,则class A
没有正确的复制构造函数,因此会删除两个实例的令牌。
这导致双重删除,因为第一个实例中的指针没有改变。