class A
{
public:
A(){}
~A(){}
void DoSomething(int x){}
};
void func(int i)
{
A *pa = new A();
pa->DoSomething(i);
delete pa;
}
你们看到这段代码有什么问题吗? 我只能看到以下两点:
还有其他想法吗?
答案 0 :(得分:9)
应该在堆栈而不是堆上创建类
A
的对象。
是的,pa
应该创建为自动变量(在堆栈上)而不是动态(在堆上)。
但是,写入也是错误的,因为它不是异常安全的。如果pa->DoSomething(i)
抛出异常,您将泄漏pa
指向的对象。
管理资源生命周期的正确方法是使用范围限制资源管理(SBRM;也称为资源获取是初始化)。管理动态分配对象的RAII方法是使用智能指针:
void func(int i)
{
std::auto_ptr<A> pa(new A());
pa->DoSomething(i);
}
手动资源管理既脆弱又危险,因为它很容易出错。在这个简单的例子中,很容易看出pa->DoSomething(i)
没有抛出异常,因为它根本不做任何事情。但在几乎每一个真正的程序中,都不是那么容易。
随着程序规模和复杂性的增加,手动资源管理很快变得非常困难。使用范围限制资源管理进行自动资源管理可以很好地扩展。
func
仅针对课程A
的对象进行操作,并且应该成为A
的成员。
这不正确。如果需要访问对象的内部状态,则只应将函数实现为成员函数。这意味着您应该尽可能将函数实现为非成员函数。
您拥有的成员函数越多,彻底测试类所需的工作就越多,因为有更多方法可以修改类的内部状态。
Herb Sutter解释了这一原则,打破了他本周大师文章"Monoliths Unstrung."中的std::string
课程。{/ p>
答案 1 :(得分:2)
执行A :: DoSomething()时,func()上发生任何异常都会导致内存泄漏。使用智能指针(例如std :: auto_ptr)
答案 2 :(得分:0)
此外,需要复制构造函数,赋值运算符或析构函数的类通常需要全部三个(我知道,这个是空的 - 只是说)。
答案 3 :(得分:0)
这是真正的代码吗?然后无状态类是完全多余的,void DoSomething(int x)
应该是正常的函数。如果没有,请发布真实的代码,否则很难提供进一步的建议。