假设您有以下代码:
int main(int argc, char** argv) {
Foo f;
while (true) {
f.doSomething();
}
}
以下两种 Foo 实现中哪一个是首选?
解决方案一:
class Foo {
private:
void doIt(Bar& data);
public:
void doSomething() {
Bar _data;
doIt(_data);
}
};
解决方案2:
class Foo {
private:
Bar _data;
void doIt(Bar& data);
public:
void doSomething() {
doIt(_data);
}
};
用简单的英语来说:如果我有一个类,其中有一个经常被调用的方法,并且该方法定义了大量的临时数据(复杂类的一个对象,或大量简单对象),我应该声明它吗?数据作为类的私有成员?
一方面,这将节省每次调用时构造、初始化和销毁数据所花费的时间,从而提高性能。另一方面,它践踏了“私有成员=对象的状态”原则,并且可能使代码更难理解。
答案是否取决于 Bar 类的大小/复杂性?声明的对象数量怎么样?什么时候好处会超过坏处?
从设计的角度来看,如果该数据不是对象状态的一部分,则使用临时数据会更干净,并且应该是首选。
在实际分析应用程序之前,切勿根据性能做出设计选择。您可能会发现您最终得到了一个更糟糕的设计,实际上并不比原始设计的性能更好。
对于所有建议在构造/销毁成本较高时重用对象的答案,重要的是要注意,如果必须从一个调用到另一个调用重用对象,则在许多情况下,必须在方法调用之间将对象重置为有效状态这也是有代价的。在许多这样的情况下,重置的成本可以与建设/破坏相媲美。
如果不在调用之间重置对象状态,则两个解决方案可能会产生不同的结果,因为在第一次调用中,参数将被初始化,并且方法调用之间的状态可能会有所不同。
线程安全也对这个决定有很大影响。函数内的自动变量是在每个线程的堆栈中创建的,因此本质上是线程安全的。任何推送这些局部变量以便可以在不同调用之间重用的优化都会使线程安全变得复杂,甚至可能因争用而导致性能损失,从而使整体性能恶化。
最后,如果您想在方法调用之间保留对象,我仍然不会将其设为类的私有成员(它不是类的一部分),而是将其设为实现细节(静态函数变量,在未命名命名空间中全局)实现 doOperation 的编译单元,PIMPL 的成员...[前 2 个共享所有对象的数据,而后者仅适用于同一对象中的所有调用])类的用户不关心你如何解决问题(只要您安全地执行此操作,并记录该类不是线程安全的)。
// foo.h
class Foo {
public:
void doOperation();
private:
void doIt( Bar& data );
};
// foo.cpp
void Foo::doOperation()
{
static Bar reusable_data;
doIt( reusable_data );
}
// else foo.cpp
namespace {
Bar reusable_global_data;
}
void Foo::doOperation()
{
doIt( reusable_global_data );
}
// pimpl foo.h
class Foo {
public:
void doOperation();
private:
class impl_t;
boost::scoped_ptr<impl_t> impl;
};
// foo.cpp
class Foo::impl_t {
private:
Bar reusable;
public:
void doIt(); // uses this->reusable instead of argument
};
void Foo::doOperation() {
impl->doIt();
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)