何时使用 "new" 创建类实例的良好策略是什么?我已经从事C++业余编程一段时间了,但我仍然不确定什么时候最好这样做:
MyClass thing(param1, param2);
关于这个问题:
MyClass* thing;
thing = new MyClass(param1, param2);
有什么建议吗?
何时使用 "new" 创建类实例的良好策略是什么?我已经从事C++业余编程一段时间了,但我仍然不确定什么时候最好这样做:
MyClass thing(param1, param2);
关于这个问题:
MyClass* thing;
thing = new MyClass(param1, param2);
有什么建议吗?
在设计方面,尽可能使用自动(堆栈)分配。每当需要将对象的生存期延长超过一定范围时,请动态地对其进行分配。
即使如此,也永远不要直接进行动态分配。始终将它们包装到某种实现作用域绑定资源管理(SBRM)的包装器中,首次以愚蠢/笨拙的名称资源获取是初始化(RAII)而闻名。也就是说,动态分配应该保留在自动对象中,这些对象将自动清理!
一个很好的例子是 std::vector:您无法泄漏 vector 中的内存,因为其析构函数在应该释放内存的每种情况下都会运行,并且它将为您释放该内存。auto_ptr 是标准库中可用的第一个和唯一的智能指针,但它非常糟糕。最好使用 shared_ptr 或许多其他流行的智能指针,这些指针可在 Boost 和/或 TR1 和/或 C++0x 中找到。
在性能方面,堆栈上分配的对象可以非常快速地完成(堆栈大小按函数调用增加,因此所有所需内存已经通过简单的指针移动预先分配)。相反,动态分配通常需要更多时间。可以通过自定义分配方案实现快速动态分配,但即使是最好的方案也比堆栈分配慢得多。
偶尔,您可能会发现花费太多时间在对象复制上。在这种情况下,值得动态地进行分配并仅移动指针。但请注意,我说的是“找到”。这种更改是通过分析和测量而不是猜测来找到的。
因此:尽可能使用自动分配,必要时使用动态分配。
一个经验法则是:如果不使用new
也能正常工作,就不要使用new
。
MyClass thing(param1, param2);
中没有指针参与。如果你可以像使用 int
一样使用对象,那么你应该这样做。 - David Titarenco&myStackobj
,而且似乎能够工作。 - Javiernew
。 如果对象很大,您可能想使用 new
。首先,问问自己一个问题,当另一个函数需要它时,复制对象是否有意义?
如果复制对象有意义,最好的方法是在堆栈上创建所有内容或作为成员变量,然后在需要时只需传递副本。
如果复制对象没有意义,您将需要使用new
表单,以便可以安全地传递指向对象的指针。您必须使用指针(或引用),因为如上所述,复制对象没有意义。
我知道有两个例外:
如果您知道对象在当前函数完成后不会被使用,可以在堆栈上创建对象,以便删除它。只要确保之后没有人持有指向它的指针即可!(我很少发现这种情况,但它确实会发生)
如果对象由另一个类在内部使用,该类本身不应该被复制,则可以将其放入成员变量中。由于包含它的对象不会被复制,并且仅供内部使用,因此这将是安全的。
MyClass thing(param1, param2); //memory for thing is allocated on the process stack(static allocation)
MyClass* thing;
thing = new MyClass(param1, param2); //memory is allocated dynamically on the heap(free store) for thing
区别在于这里:
int main()
{
{
MyClass thing(param1, param2); //thing is local to the scope
} //destructor called for thing
//cannot access thing (thing doesn't exist)
}
int main()
{
{
MyClass* thing;
thing = new MyClass(param1, param2);
}
//the object pointed to by thing still exists
//Memory leak
}
thing
。:) 它仍然存在,但由于没有指针指向它,它永远不会被释放。 - GManNickGthing
指向的MyClass*将不再存在于您声明它的位置,因为它是一个局部变量,已经超出了作用域。 MyClass对象——thing
曾经指向的对象,将持久存在,并且正是这个对象导致了内存泄漏。 - Larry Wangnew
。总是将其隐藏在 RAII 包装器后面,这样当包装器超出范围时它就会被删除。 - jalf