3

我正在尝试在我的容器库中实现以下优化:

  • 插入左值引用元素时,将其复制到内部存储;
  • 但是在插入右值引用元素时,如果支持,请移动它。

优化应该是有用的,例如,如果包含的元素类型是类似std::vector的,如果可能的话移动会大大加快速度。

但是,到目前为止,我无法为此设计任何工作方案。我的容器相当复杂,所以我不能insert()多次重复代码:它很大。我想将所有“真实”代码保留在某个内部助手中,比如说do_insert()(可能是模板化的),并且各种insert()类似的函数只会用不同的参数调用它。

我最好的赌注代码(原型,当然,没有做任何真实的事情):

#include <iostream>
#include <utility>

struct element
{
  element () { };
  element (element&&) { std::cerr << "moving\n"; }
};

struct container
{
  void  insert (const element& value)
  {  do_insert (value);  }

  void  insert (element&& value)
  {  do_insert (std::move (value));  }

private:
  template <typename Arg>
  void  do_insert (Arg arg)
  {  element  x (arg);  }
};

int
main ()
{
  {
    // Shouldn't move.
    container  c;
    element x;
    c.insert (x);
  }

  {
    // Should move.
    container  c;
    c.insert (element ());
  }
}

但是,这至少不适用于 GCC 4.4 和 4.5:它永远不会在 stderr 上打印“移动”。或者是我想要的不可能实现,这就是为什么emplace()首先存在类似功能的原因?

4

3 回答 3

1

我认为您可能需要转发论点:

  template <typename Arg>
  void  do_insert (Arg&& arg)
  {  element  x (std::forward<Arg>(arg));  }

完整代码:

#include <iostream>
#include <utility>

struct element
{
  element () { };
  element (const element&) { std::cerr << "copying\n"; }
  element (element&&) { std::cerr << "moving\n"; }
};

struct container
{
  void  insert (const element& value)
  {  do_insert (value);  }

  void  insert (element&& value)
  {  do_insert (std::move(value));  }

private:
  template <typename Arg>
  void  do_insert (Arg&& arg)
  {  element  x (std::forward<Arg>(arg));  }
};

int
main ()
{
  {
    // Shouldn't move.
    container  c;
    element x;
    c.insert (x);
  }
  {
    // Should move.
    container  c;
    c.insert (element ());
  }
}

您可能会寻找的关键字是“完美转发”。

于 2010-04-24T14:59:19.797 回答
0

我建议复制它在您的 STL 实现(或 GNU,无论如何都应该能够在线阅读)中完成的方式。

  template <typename Arg>
  void  do_insert (Arg arg)
  {  element  x (move(arg));  }

可能会成功。

这个功能是独立的emplace,你是正确的,它在标准库中工作。

编辑我做了一些改变并发现

  • 当您收到两条消息时,每次插入都有一条
  • 第二次插入似乎很好
  • 第一个生成一个虚假move但原始对象没有移动。所以专注于寻找一个正在被移动的临时......这实际上并不是一件坏事。

.

#include <iostream>
#include <utility>

struct element
{
  element () : moved(false) { };
  element (element&&) { moved = true; std::cerr << "moving\n"; }
  bool moved;
};

struct container
{
  void  insert (const element& value)
  {  do_insert (value);  }

  void  insert (element&& value)
  {  do_insert (std::move (value));  }

private:
  template <typename Arg>
  void  do_insert (Arg arg)
  {  element  x (std::move(arg));  }
};

int
main ()
{
  std::cerr << "try 1\n";
  {
    // Shouldn't move.
    container  c;
    element x;
    c.insert (x);
    std::cerr << x.moved << "\n";
  }

  std::cerr << "try 2\n";
  {
    // Should move.
    container  c;
    c.insert (element ());
  }
}
于 2010-04-24T15:09:52.320 回答
0

我不能说我理解为什么这有效而其他一些代码无效,但这似乎可以解决问题(由于 Potatoswatter 的提示而创建):

#include <iostream>
#include <utility>

struct element
{
  element () { };
  element (const element&) { std::cerr << "copying\n"; }
  element (element&&) { std::cerr << "moving\n"; }
};

struct container
{
  void  insert (const element& value)
  {  do_insert <const element&> (value);  }

  void  insert (element&& value)
  {  do_insert <element&&> (std::forward <element&&> (value));  }

private:
  template <typename Arg>
  void  do_insert (Arg arg)
  {  element  x (std::forward <Arg> (arg));  }
};

int
main ()
{
  std::cerr << "1\n";
  {
    // Shouldn't move.
    container  c;
    element x;
    c.insert (x);
  }

  std::cerr << "2\n";
  {
    // Should move.
    container  c;
    c.insert (element ());
  }
}

我使用 GCC 4.4 和 4.5 得到以下输出:

1
copying
2
moving
于 2010-04-24T16:03:36.680 回答