转换运算符对复制构造函数的偏好从 C++14 更改为 C++17?

问题描述 投票:0回答:1

我正在玩下面的代码。

#include <iostream>

struct To
{
    To() = default;
    To(const struct From&) {std::cout << "Constructor called\n";}
    To(const To&) {std::cout << "Copy constructor called\n";}
};

struct From
{
    operator To(){std::cout << "Conversion called\n"; return To();}
};

int main()
{
    From f;
    To t(f);
    To t1 = f;
    To t2{To(f)};
}

如果我使用

-std=c++14
GCCClang 同意以下输出。

Constructor called
Conversion called
Constructor called

但是,如果我用

-std=c++17
编译,两个编译器都同意

Conversion called
Conversion called
Conversion called

我知道将几个预期的输出行减少到仅输出 3 行是由于复制省略(如果我错了请纠正我),但我无法弄清楚 C++17 中导致此输出的更改.究竟是什么标准变化引发了这一变化?

c++ c++17 c++14 language-lawyer conversion-operator
1个回答
0
投票

与 -std=c++14 相比,使用 -std=c++17 编译时,您在代码输出中观察到的变化是由于 C++17 中引入的称为保证复制省略的功能.

在 C++14 及更早版本中,复制省略是允许的,但不保证。这意味着编译器可以选择在满足某些条件时省略(优化掉)复制或移动操作,但这不是必需的。然而,在 C++17 中,引入了有保证的复制省略,它要求在特定场景中省略某些复制或移动操作。

在您提供的代码中,当您使用 -std=c++17 进行编译时,保证的复制省略功能将启动,并且在 To t、To t1 和 To t2 的所有三种情况下都省略了 To 的复制构造函数由 From f 构建。相反,编译器使用 To(const struct From&) 构造函数直接从 From 对象构造 To 对象,这就是为什么您会在输出中看到三次“Conversion called”。

在C++14中,To的拷贝构造函数没有被省略,在输出中看到“Constructor called”,说明正在调用拷贝构造函数从From对象构造To对象。

因此,引发此行为的标准变化是在 C++17 中引入了有保证的复制省略,它要求在特定场景中省略某些复制或移动操作,以实现更高效的代码生成。

© www.soinside.com 2019 - 2024. All rights reserved.