我使用new Time(1,0,0)
初始化SmartPtr类。
//main.cpp
int main()
{
SmartPtr pTime0(new Time(0,0,1));
}
我无法在new Time(1,0,0)
上调用删除。一切正常,程序符合并运行。但我很困惑 - 应该/不应该在哪里delete Time(1,0,0)
?
我不明白在这里创建和删除临时对象的概念。
我知道每当我写new
某处我必须写delete
!
有人可以解释delete Time(1,0,0)
发生在哪里吗?
SmartPtr pTime0(新时间(0,0,1))< - new
这里返回一个指向新分配内存的指针,然后在ctor中我第二次分配new
内存??
//SmartPtr.cpp
SmartPtr::SmartPtr(Pointee * p):_pointee(new Pointee(*p))
{}
SmartPtr::~SmartPtr()
{
delete _pointee;
}
答案 0 :(得分:2)
我不知道您SmartPtr
课程的详细信息。
无论如何,如果你有这样的构造函数:
SmartPtr::SmartPtr(Pointee * p):_pointee(new Pointee(*p)) {}
这是析构函数:
SmartPtr::~SmartPtr() { delete _pointee; }
然后使用此代码:
SmartPtr pTime0(new Time(0,0,1));
泄漏了Time(0,0,1)
的一个实例。
事实上,您还有一个new
而非delete
(2 new
s和1 delete
):
步骤1:你调用new Time(0,0,1)
并在堆上创建一个新对象
(new
count == 1)
步骤2:您将此指针传递给SmartPtr
构造函数,深层复制以前创建的对象并在堆上分配新副本,并通过其{跟踪此副本{1}}数据成员。
(_pointee
count == 2)
步骤3:当new
析构函数运行时,它SmartPtr
是delete
数据成员指向的实例,但是你泄露了 firts {{ 1}}在_pointee
的堆上创建
(Time(...)
count == 1; new Time(0,0,1)
count == 2)
可能的解决办法就是拥有这个构造函数:
delete
在这些情况下识别潜在泄漏的一种简单方法是在new
类构造函数和析构函数中放置一些控制台跟踪输出,并检查析构函数的跟踪输出是否与构造函数的跟踪输出匹配,例如:
SmartPtr::SmartPtr(Pointee * p)
: _pointee(p) // <--- transfer ownerhsip (no deep copies) !
{}
Time
字符串的总数应与Time::Time(....)
{
// Do construction work....
std::cout << "Time constructor\n";
}
Time::~Time(....)
{
// Do destructor work....
std::cout << "Time destructor\n";
}
字符串的总数相匹配。
答案 1 :(得分:1)
两种解决方法:
方法A,调用者分配,SmartPtr取得所有权:
SmartPtr::SmartPtr(Pointee * p):_pointee(p)
{
}
方法B,调用者提供内容,SmartPtr分配:
SmartPtr::SmartPtr(Pointee v):_pointee(new Pointee(std::move(v)))
{
}
析构函数保持不变:
SmartPtr::~SmartPtr()
{
delete _pointee;
}
答案 2 :(得分:0)
表达式new Time(0,0,1)
创建一个指向堆上永久对象的临时指针。确实会自动销毁临时指针(这是一个无操作),使对象仍然在堆上但未引用。发生了泄漏。
为了防止泄漏,请确保将指针存储在某处,并确保最终在其上调用删除。
答案 3 :(得分:0)
您可以根据从不输入新的原则编写应用程序。
将它与现有的智能指针结合起来,它就变成了:
#include <memory> // this is where the smart-pointers live
#include "Time.h" // or whatever header defines your "Time" class
int main()
{
// note that make_shared is essentially a forwarding constructor,
// give it whatever parameters Time's constructor would take
auto p = std::make_shared<Time>(0,0,1);
// use p here
}
任何事情都不会泄漏。
“从不输入新”应适用于所有应用程序编程, 如果你必须写一个低级别,唯一的例外 资源管理库。
请注意,如果一个类进行资源管理,它应该是它的 唯一的功能。
所有其他课程都应遵循rule of zero