根据cppreference,std::vector::emplace_back
只有一个签名,即:
template< class... Args >
reference emplace_back( Args&&... args );
在描述中,它说emplace_back
应该将其每个参数转发给vector
中类型的构造函数。然而,当我使用gcc 12.2测试以下代码时,它成功地编译了:
#include <iostream>
#include <vector>
class Foo
{
public:
int x;
int y;
Foo(int x, int y) : x(x), y(y)
{}
};
int main()
{
std::vector<Foo> foos;
Foo foo(1, 2);
foos.push_back(std::move(foo));
foos.emplace_back(foo); // weird
}
(请参阅编译器资源管理器(
我原以为foos.emplace_back(foo);
行编译失败。似乎emplace_back
有这种过载:
template< class T >
reference emplace_back( T& arg );
文档中没有提到。我是遗漏了什么,还是这只是一个编译器扩展?
foos.emplace_back(foo); // weird
真奇怪!您请求emplace_back
,这意味着您正在调用构造函数,并将foo
传递给构造函数。因此,您正在调用复制构造函数。push_back
也会这么做!
这是一个隐式定义的默认复制构造函数,请参阅复制构造函数上的cppreference:
如果没有为类类型(结构、类或联合(提供用户定义的复制构造函数,编译器将始终将复制构造函数声明为其类的非显式内联公共成员。
您没有定义复制构造函数,所以编译器按照C++的要求为您定义了复制构造函数。你可以避免这种情况,并使你的编译失败:
class Foo
{
public:
int x;
int y;
Foo(int x, int y) : x(x), y(y)
{}
//! Explicitly deleted default copy constructor.
Foo(const Foo&) = delete;
};
foos.push_back(std::move(foo));
他正在调用move构造函数。请注意,您在离开foo
之后使用它,这或多或少是非法的(将std::move
扔到foo
意味着foo
不再应该拥有任何资源。(
如果您真的只想删除move构造函数,语法基本相同:Foo(Foo&&) = delete;
。
template< class... Args >
reference emplace_back( Args&&... args );
可以推断为类似(用Args = Foo&
(的东西
reference emplace_back( Foo& && args[0] );
崩溃为
reference emplace_back( Foo& args[0] );