提问人:24n8 提问时间:12/23/2018 最后编辑:max6624n8 更新时间:4/9/2019 访问量:6840
emplace_back() 与 push_back 插入 std::vector 时
emplace_back() vs push_back when inserting a pair into std::vector
问:
我定义了以下内容
std::vector<std::pair<int,int> > my_vec;
my_vec.push_back( {1,2} ); //this works
my_vec.emplace_back( {1,2} ); // this doesn't work
std::pair<int,int> temp_pair = {1,2};
my_vec.emplace_back( temp_pair ); //this works
我正在用 c++11 编译。第三行是有问题的,但我认为你可以在任何地方使用,但这显然是错误的。为什么第三行不起作用?emplace_back()
push_back()
答:
emplace_back
将可变参数包作为参数:
template< class... Args > reference emplace_back( Args&&... args );
当你这样称呼它时:你是用一个参数来称呼它,即 并且无法推断。那是因为语言是如何演变的。在 C++ 中没有类型。它是一个括起来的 init-list,可用于某些类型的初始化,但都需要知道初始化的类型。这就是工作的原因,因为 的类型是 know 并且具有匹配的构造函数。emplace_back({1, 2})
{1, 2}
Args
{1, 2}
temp_pair = {1,2};
temp_pair
(int, int)
无论如何,不应该这样使用,而是像这样使用:emplace_back
my_vec.emplace_back(1, 2);
另请注意,即使这些工作有效:
my_vec.emplace_back(std::pair<int, int>{1, 2});
my_vec.emplace_back(temp_pair);
它们不应该被使用。与push_back相比,它们没有增加任何优势。的重点是避免创建一个临时的.上述调用都会创建临时 .emplace_back
T
std::pair<int, int>
但我认为你可以在你有的任何地方使用
emplace_back()
push_back()
在大多数情况下,这是正确的。至少这是我的初衷。而且您确实可以在您的cese中使用它。你只需要稍微调整一下语法。因此,您可以使用.push_back({1, 2})
emplace_back(1, 2)
不幸的是,有一种情况你不能使用:聚合。emplace_back
struct Agg
{
int a, b;
};
auto test()
{
Agg a{1, 2}; // ok, aggregate initialization
std::vector<Agg> v;
v.emplace_back(1, 2); // doesn't work :(
}
除非为 添加构造函数,否则这不起作用。这被认为是标准中的一个开放缺陷,但不幸的是,他们找不到一个好的解决方案。问题在于大括号初始化的工作原理,如果在通用代码中使用它,可能会错过一些构造函数。有关所有细节,请查看这篇很棒的文章:为什么聚合门结构可以用大括号初始化,但不能使用与大括号初始化相同的参数列表进行放置?Agg
1) 不是表达式{1, 2}
语法
{1, 2}
与 C++ 中的其他东西相比,非常“奇怪”。
通常在 C++ 中,你有一个表达式(例如 ),并且表达式有一个推导类型......例如,如果是一个变量,则表达式的类型将是由于隐式转换→以及加法的工作原理。x + 1.2
x
int
double
int
double
现在回到:这很“奇怪”,因为尽管看起来像一个表情,但它不是......它只是语法,其含义将取决于它的使用位置。{1, 2}
从某种意义上说,这里的类型与大多数C++相反:通常在C++中,它是“in”→“out”(类型从组件中“出现”),但这里是“out”→“in”(类型在组件中“注入”)。
文本本身的意义不足以被编译(根据使用位置的不同,它可能意味着不同的东西)。{1, 2}
所有这一切都归结为一个事实,即不能像表达式一样使用,即使规则经过精心设计以欺骗您认为它确实如此。{1, 2}
2) 接受构造函数参数emplace_back
emplace_back
被设计为能够直接在容器的最终位置内构建对象......预期的参数是构造函数的参数,这样做是为了避免创建一个临时对象,只是为了能够为最终目标制作一个副本,然后把它扔掉。
因此,的预期参数是 和 ...没有单一的东西,因为不构建一个临时的单一东西正是设计的原因。emplace_back
1
2
emplace_back
可以传递实例,因为包含的类型具有复制构造函数,并且该实例被视为复制(移动)构造函数的参数,而不是要复制(移动)到目标(预期)的对象。在这种情况下执行的操作是相同的,但观点不同。emplace_back
push_back
后果
总而言之:不能使用,因为它可以接受任何东西(所以没有提供足够的“上下文”),而且语法没有足够的意义。 相反,可以接受它,因为它需要特定的类型,这为解释语法提供了足够的上下文。
这是一个简化的解释,但像往常一样,C++ 朝着一个更加复杂和特殊情况的方向发展,所以我可以理解为什么事情对你来说不清楚。emplace_back
{1, 2}
push_back
{1, 2}
然而,关键的一点是,这并不意味着要接受一个完整的对象......为此,.如果要传递 CONSTRUCTOR PARAMETERS 以在容器中构建最终对象,则应使用新构造。emplace_back
push_back
emplace_back
评论
my_vec.emplace_back(1,2);
({1,2})