为什么访问std::initializer_list
不允许我们更改其内容?当std::initializer_list
用于其主要目的(初始化容器)时,它是一个很大的缺点,因为它的使用会导致过多的复制构造/复制分配,而不是移动构造/动赋值。
#include <initializer_list>
#include <iostream>
#include <vector>
#include <cstdlib>
struct A
{
A() = default;
A(A const &) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
A(A &&) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
A & operator = (A const &) { std::cout << __PRETTY_FUNCTION__ << std::endl; return *this; }
A & operator = (A &&) { std::cout << __PRETTY_FUNCTION__ << std::endl; return *this; }
};
int
main()
{
std::vector< A >{A{}, A{}, A{}};
return EXIT_SUCCESS;
}
Output(正如所料):
A::A(const A &)
A::A(const A &)
A::A(const A &)
为什么它的设计如此受限?
答案 0 :(得分:6)
最近有proposal for movable initializer lists,特别是作者说:
std::initializer_list
是在2005年(N1890)到2007年(N2215)之前设计的 移动语义在2009年左右成熟。当时,没有预料到复制语义 对于类似普通价值的类来说,它是不够的,甚至是次优的。有一个2008年 提议N2801 初始化程序列出并移动语义但是当时C ++ 0x已经感觉到正在下滑,到2011年情况已经变冷了。
答案 1 :(得分:4)
好的(如果不幸的话)安东回答。
这是libc ++中实现的源代码:
template <class _Tp, class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY
vector<_Tp, _Allocator>::vector(initializer_list<value_type> __il)
{
#if _LIBCPP_DEBUG_LEVEL >= 2
__get_db()->__insert_c(this);
#endif
if (__il.size() > 0)
{
allocate(__il.size());
__construct_at_end(__il.begin(), __il.end());
}
}
没有移动迭代器,因此复制构造。
如果它有用,这里是一个使用可变参数列表的解决方法:
#include <initializer_list>
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <utility>
#include <cstdlib>
struct A
{
A() noexcept{ std::cout << __PRETTY_FUNCTION__ << std::endl; }
A(A const &) noexcept { std::cout << __PRETTY_FUNCTION__ << std::endl; }
A & operator = (A const &) noexcept { std::cout << __PRETTY_FUNCTION__ << std::endl; return *this; }
A(A &&) noexcept { std::cout << __PRETTY_FUNCTION__ << std::endl; }
A & operator = (A &&) noexcept { std::cout << __PRETTY_FUNCTION__ << std::endl; return *this; }
};
template<class T, class...Args>
void append_it(std::vector<T>& v)
{
}
template<class T, class...Args>
void append_it(std::vector<T>& v, T&& t1, Args&&...args)
{
v.push_back(std::move(t1));
append_it(v, std::forward<Args&&>(args)...);
}
template<class T, class...Args>
std::vector<T> make_vector(T&& t1, Args&&...args)
{
std::vector<T> result;
result.reserve(1 + sizeof...(args));
result.push_back(std::move(t1));
append_it(result, std::forward<Args&&>(args)...);
return result;
}
int
main()
{
auto v2 = make_vector( A{}, A{}, A{} );
return EXIT_SUCCESS;
}