为什么要访问 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;
}
产量 (如预期的那样):
A::A(const A &)
A::A(const A &)
A::A(const A &)
为什么它的设计受到如此限制?
最近有一个 可移动初始化列表的提议特别是作者说:
std::initializer_list
是在2005年(N1890)到2007年(N2215)之前设计的
移动语义在2009年左右成熟。当时,没有预料到复制语义
对于类似普通价值的类而言,这将是不够的,甚至是次优的。有一个2008年
建议N2801 初始化程序列出并移动语义 但是C ++ 0x当时已经感觉到正在下滑,到2011年,这个案子已经变冷了。
安东好的(如果不幸的话)答案。
这是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;
}