效率vs封装:孰优孰劣

Efficiency vs Encapsulation: Which is preferred?

本文关键字:vs 封装 效率      更新时间:2023-10-16

在类中实现良好的封装将确保没有外部力量可以修改对象的内部。在c++中,这意味着类应该自己分配所有需要动态分配的对象。如果必须对这样的对象进行复制,则意味着也必须复制许多内部属性(不仅仅是指针)。这可能会导致某些程序的大量开销。下面是一个例子:

class A { };
class B : public A {
private:
  std::vector< const A* > m_children;
public:
  B( ) : m_children( 0 ) { }
  B( const B& src ) : m_children( src.m_children.size( ) ) { // Make it a copy of src
    for ( unsigned int i = 0; i < m_children.size( ); i++ )
      // Make a full copy of src element (and all children, not implemented here)
      m_children[ i ] = copyOf( *src.m_children[ i ] ); // Dynamically allocates copy!
  }
  ~B( ){ // Deallocate all children
    while ( !m_children.empty( ) ){
      delete m_children.back( ); // Get last element in array
      m_children.pop_back( ); // Remove last element
    }
  }
  void addChild( const B& child ) {
    m_children.push_back( new B( child ) ); // Notice dynamic allocation
  }
};
B build( int x ) {
  B b;
  if ( x != 0 ) b.addChild( build( x - 1 ) );
  return b;
}
int main( int argc, char **argv ) {
  B b = build( 10 ); // Make 10 generations with 1 child each
}

每次将子节点添加到B时,它将再次被完全分配(包括它的所有子节点)。这确实提供了良好的封装,因为无论在什么情况下,父指针都是唯一可以实际修改其子指针(或释放指针)的对象。此外,它对在自身毁灭时删除这些儿童负有全部责任。这在内存管理方面不是很有效。对于每个build()函数,必须动态地创建和删除大量附加对象。

为什么有两种可能性:
要么我在这里遗漏了什么,这可以通过实现良好的封装和效率来完成。如果是这样,请告诉我。
或者,这是唯一的方法,然后:哪种方法通常是首选的;强封装(没有外部访问),或在类外部分配对象,以便内存操作发生较少,但"外部世界"可以访问这些指针及其对象(这是不太安全的)?

应该使用move语义来避免不必要的复制。你需要给class B添加一个move构造函数。

class B
{
    B(B&& rhs)
   {
       std::swap(m_children, rhs.m_children);
   }
}

然后您可以将addChild()函数更改为:

class B
{
    void addChild(B child) 
    {
        m_children.push_back( new B( std::move(child) ) );
    }
}

为什么会这样?在build()函数中,您将临时传递给addChild()函数。这将调用move构造函数,然后继续移动对象。

LIVE DEMO -删除复制构造函数,因此您可以看到没有复制。