【问题标题】:C++ STL container and in-place constructionC++ STL 容器和就地构造
【发布时间】:2010-01-20 09:28:23
【问题描述】:

请考虑以下几点:

class CMyClass
{
public:
  CMyClass()
  {
    printf( "Constructor\n" );
  }
  CMyClass( const CMyClass& )
  {
    printf( "Copy constructor\n" );
  }
};

int main()
{
  std::list<CMyClass> listMyClass;

  listMyClass.resize( 1 );

  return 0;
}

它产生以下输出:

构造函数

复制构造函数

现在我的问题是:如何避免复制构造函数?或者换一种说法:如何在没有不必要的复制操作的情况下在 STL 容器中创建对象。有没有办法使用默认构造函数进行“就地”构造?


更新 - 到目前为止的答案:

  1. 做不到
  2. 使用指针或智能指针 而是。

智能指针对我的应用程序来说太过分了。但我真的很想知道为什么不能这样做。这似乎是一件显而易见的事情。还有其他想法吗?如果可行的话,我什至会接受一个讨厌的黑客攻击......


解决方案

我想我刚刚从这里提出的所有 cmets 和答案中找到了我的问题的解决方案。解决方案是构造一个空对象并保留它,唯一的目的是稍后使用它来制作干净的副本。然后,您可以使用其中一种获取引用的方法(如 push_back 或 insert)。这仍然为每个插入的新对象调用复制构造函数,但至少它不是默认构造函数和复制构造函数:

int main()
{
  CMyClass Empty;

  std::list<CMyClass> listMyClass;

  for ( int c=0; c<10; ++c )
  {
    listMyClass.push_back( Empty );
  }

  return 0;
}

【问题讨论】:

  • 这似乎是一个显而易见的事情,但从功能的角度来看,这并不重要,并且有几个算法(排序、删除、...)也使用复制,所以要准备好被复制;)(另见devx.com/tips/Tip/13606
  • 显而易见的事情?这是为什么?为什么复制有问题?
  • 明显吗?如果您调用mylist.resize(10),如果它们不是副本,您会如何期望得到十个不同的对象?
  • 我要做的就是在列表中构造一个新对象。 STL 所做的就是先构造一个临时对象,然后使用复制构造函数复制临时对象。这个副本是不必要的浪费时间。 mylist.resize(10) 的替代实现可以调用默认构造函数 10 次。它所做的是调用默认构造函数一次,然后调用复制构造函数 10 次。这对于 10 个对象 (10%) 来说是很小的开销,但如果您必须一次添加一个对象,则开销会增加一倍 (100%)。
  • 好吧,您可能希望标准容器表现得像那样,但事实并非如此。在某些情况下,编译器可能会忽略对复制 ctor 的调用,但如果您不想依赖它,为什么不使用指针,就像每个人都建议的那样?

标签: c++ stl


【解决方案1】:

根据设计,所有 C++ 标准库容器都存储副本。因此,如果您希望将值存储在容器中,就无法避免调用复制构造函数——唯一的出路是存储指针。如果您想减少复制的开销,请研究引用计数的使用。

【讨论】:

    【解决方案2】:

    抱歉,目前没有 std::list 和类似容器。 (但是如果你真的需要,你可以编写自己的稍微不同的容器,并且仍然遵循 STL 接口的其余部分。)

    但是,您不必使用默认 ctor:

    std::list<CMyClass> listMyClass;
    listMyClass.resize(1, obj_to_copy_from);
    

    如:

    std::list<CMyClass> listMyClass;
    listMyClass.resize(1, CMyClass(use, specific, ctor));
    

    调整大小如下:

    void list<T>::resize(size_type new_size, T copy_from = T());
    

    默认情况下会创建一个新对象(使用默认 ctor)。

    【讨论】:

      【解决方案3】:

      使用指针

      std::list<CMyClass*> listMyClass;
      

      【讨论】:

      • 更好:使用智能指针,自动创建/销毁相关对象
      • 只是不是 auto_ptr。这会导致坏事发生。
      【解决方案4】:

      如果向量允许在调整大小时使用默认构造函数初始化新元素,这将很有用,但不支持。如果你真的需要这个,实现自定义容器 - 没有其他办法。

      【讨论】:

        【解决方案5】:

        使用指针或智能指针(boost::shared_ptr 而不是 auto_ptr)

        【讨论】:

          【解决方案6】:

          http://swagatata.tumblr.com/post/5896332725/vector-construction

          即使你这样做了

          std::list<classname> objectname(100);
          

          构造函数将被调用一次,然后将使用复制构造函数构造 100 个对象。

          【讨论】:

            【解决方案7】:

            可以在c11中做,对于旧版本,vesry simple可以改进

            矢量

            myclas: public vector<A>
            {
                push_back(Aconstructor_parameters)
                {
                   new(_Mylast++) A(Aconstructor_parameters);
                }
            };
            

            使用时请确保您已使用reserve() 分配内存

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2021-12-09
              • 2015-05-21
              • 1970-01-01
              • 2014-02-03
              • 1970-01-01
              • 1970-01-01
              • 2011-02-07
              相关资源
              最近更新 更多