在标准中,有一些地方可以复制或移动对象以初始化对象。复制省略(有时称为返回值优化)是一种优化,通过该优化,在某些特定情况下,即使标准规定必须进行复制,也允许编译器避免复制或移动。
考虑以下功能:
std::string get_string() { return std::string("我是绳子。"); }
根据标准的严格措辞,此函数将初始化一个临时std::string对象,然后将其复制/移动到返回值对象中,然后销毁该临时对象。该标准非常清楚,这就是解释代码的方式。
复制省略是一条规则,它允许C ++编译器忽略临时文件的创建及其后续的复制/销毁。也就是说,编译器可以为临时变量获取初始化表达式,然后直接从中初始化函数的返回值。这显然可以节省性能。
但是,它确实对用户有两个明显的影响:
该类型必须具有将被调用的复制/移动构造函数。即使编译器取消复制/移动,该类型仍必须能够被复制/移动。
在可能发生省略的情况下,不能保证复制/移动构造函数的副作用。考虑以下:
struct my_type { my_type() = default; my_type(const my_type &) {std::cout <<"Copying\n";} my_type(my_type &&) {std::cout <<"Moving\n";} }; my_type func() { return my_type(); }
电话会func做什么?好吧,它永远不会打印“正在复制”,因为临时是一个右值并且my_type是可移动的类型。那么它会打印“ Moving”吗?
如果没有复制省略规则,则必须始终打印“ Moving”(移动)。但是,由于存在复制省略规则,因此可以调用或可以不调用move构造函数;它取决于实现。
因此,在可能省略的上下文中,您不能依赖于复制/移动构造函数的调用。
因为省略是一种优化,所以您的编译器可能并不在所有情况下都支持省略。而且,无论编译器是否忽略特定情况,类型都必须仍然支持被忽略的操作。因此,如果省略了复制构造,则该类型仍必须具有一个复制构造函数,即使不会被调用。