私有成员与C++中的临时变量

5 c++

假设您有以下代码:

int main(int argc, char** argv) {
    Foo f;
    while (true) {
        f.doSomething();
    }
}
Run Code Online (Sandbox Code Playgroud)

Foo的以下两种实现中的哪一种是首选?

解决方案1:

class Foo {
    private:
        void doIt(Bar& data);
    public:
        void doSomething() {
            Bar _data;
            doIt(_data);
        }
};
Run Code Online (Sandbox Code Playgroud)

解决方案2:

class Foo {
    private:
        Bar _data;
        void doIt(Bar& data);
    public:
        void doSomething() {
            doIt(_data);
        }
};
Run Code Online (Sandbox Code Playgroud)

用简单的英语:如果我有一个类经常被调用的方法,并且这个方法定义了大量的临时数据(复杂类的一个对象,或者大量的简单对象),我应该声明这个数据作为班级的私人成员?

一方面,这将节省在每次调用上构建,初始化和破坏数据所花费的时间,从而提高性能.另一方面,它践踏了"私有成员=对象的状态"原则,并可能使代码更难理解.

答案取决于Bar类的大小/复杂程度吗?声明的对象数量如何?什么时候好处超过了缺点?

sha*_*oth 7

首先,它取决于正在解决的问题.如果需要在调用之间保留临时对象的值,则需要成员变量.如果需要在每次调用时重新初始化它们 - 请使用本地临时变量.这是一个手头的任务问题,而不是对或错.

临时变量的构造和销毁将需要一些额外的时间(与仅保持成员变量相比),具体取决于临时变量类的复杂程度以及它们的构造函数和析构函数必须执行的操作.决定成本是否显着只应在分析后进行,不要试图"以防万一"优化它.


Dav*_*eas 7

从设计的角度来看,如果数据不是对象状态的一部分,则使用临时对象更加清晰,应该是首选.

在实际分析应用程序之前,切勿在性能方面做出设计选择.您可能会发现最终设计的设计实际上并不比原设计性能更好.

对于建议在构造/销毁成本较高时建议重用对象的所有答案,重要的是要注意,如果必须将对象从一个调用重用到另一个调用,在许多情况下,必须将对象重置为方法调用之间的有效状态而且还有成本.在许多此类情况下,重置的成本可与建筑/销毁相媲美.

如果不在调用之间重置对象状态,则两个解决方案可能会产生不同的结果,因为在第一次调用中,参数将被初始化,并且方法调用之间的状态可能会有所不同.

线程安全对此决定也有很大影响.函数内部的自动变量是在每个线程的堆栈中创建的,因此本质上是线程安全的.任何推动这些局部变量以便可以在不同调用之间重用的优化都会使线程安全性变得复杂,甚至可能因为争用会导致整体性能恶化而导致性能下降.

最后,如果你想在方法调用之间保留对象,我仍然不会使它成为类的私有成员(它不是类的一部分),而是实现细节(静态函数变量,全局在未命名的命名空间中)实现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();
}
Run Code Online (Sandbox Code Playgroud)


Tod*_* Li 5

在大多数情况下,我会将_data声明为临时变量。唯一的缺点是性能,但是您将获得更多好处。如果构造和破坏确实是性能杀手,则可能要尝试使用原型模式