我正在尝试在容器库中实现以下优化:
优化应该是有用的,例如如果包含的元素类型类似于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()
- 首先存在类似函数的原因?
答案 0 :(得分:2)
我认为你可能需要提出这个论点:
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 ());
}
}
您可能寻找的关键字是“完美转发”。
答案 1 :(得分: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 ());
}
}
答案 2 :(得分: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