假设你有一个std::vector<std::string>
类型的变量,你用一个初始化器列表初始化它:
using V = std::vector<std::string>;
V v = { "Hello", "little", "world", "of", "move", "semantics" };
编译器将为每个字符串文字创建一个临时std::string
,在这些字符串上创建一个初始化列表,然后调用V
的ctor并创建向量。ctor不知道所有这些字符串都是临时的,所以它复制每个字符串。
我还没有在标准中找到任何允许向量ctor移动临时元素的东西。
是我遗漏了什么,还是使用初始化器列表会导致不必要的副本?我正在编写的类中,这个问题可能会导致代码效率低下。任何避免不必要的复制的技术都将受到极大的赞赏。
3条答案
按热度按时间eqqqjvef1#
没有办法避免从
initializer_list<string>
复制,因为标准定义了一个构造函数的调用,该构造函数从一个花括号初始化器作为实际参数,接受一个初始化器列表参数,如下所示(强调添加):C++14 §8.5.4/5
"
std::initializer_list<E>
类型的对象是从初始化器列表构造的,就好像实现分配了一个**const E
**类型的N
元素的临时数组,其中N
是初始化器列表中元素的数量IMHO这真的很不幸。
一个解决方法(对于您自己的类)是接受
initializer_list<char const*>
。下面是应用于
std::vector<string>
的解决方法的示例。为此,在不控制类代码的情况下,需要显式声明一个数据数组(实际上是一个initializer_list
)。这就像C++03一样,初始化器列表机制旨在避免:输出:
bpzcxfmw2#
经过一番思考,我想出了一个基于
mutable
的解决方案。另一个答案基本上仍然是正确的,但是可以创建一个带有可变成员的代理,以摆脱顶层的const
,然后从那里移动元素。因此,接受初始值设定项列表的方法应该重载const-ref初始值设定项列表和rvalue-ref版本,以便知道何时允许移动它们。这里有一个工作示例,它可能看起来很随意,但在我的真实用例中,它解决了这个问题。
Live example
gijlo24d3#
为了节省模板的开销,你可以不使用初始化器列表,而是使用数组的右值引用:
(The如果您知道类型,则模板参数
T
对于该技术不是必需的,但n
是必需的。)