若控制权到达主体的末尾,那个么返回nullopt会破坏什么
What would break if control-reaches-end-of-body were to return nullopt?
C++14为我们提供了自动返回类型推导,C++17有一个optional<T>
类型模板(或者类型构造函数,如果你愿意的话)。的确,optional
存在于标准库中,而不是语言本身,但是,当控件到达正文末尾时,为什么不将其用作非void函数的返回值呢?我认为:
optional<int> foo(int x)
{
if (x > 0) return 2 * x;
}
应该是分部函数的完全有效且可编译的语法,返回optional<int>
。
现在,我知道这是一个有点疯狂的想法。我的问题不是你喜欢与否,而是——假设委员会中的每个人都出于某种奇怪的原因真的喜欢它。它会与什么发生冲突?
注意:当然,如果您指定了一个非可选的返回值,这是不起作用的,但这不算作损坏。
想想以abort();
结尾的函数或具有相同效果的自定义函数。如果编译器不能静态地证明函数永远不会达到关闭的}
,这将迫使编译器生成死代码,因此与C++的一个原则相冲突,即零开销原则:不使用什么,就不付费。
特殊套管std::optional
在这里很可笑。用户应该能够编写自己的等价于std::optional
的一级代码。
这意味着从函数的末尾掉下来需要使用某种魔法来计算隐含的返回值
最简单的魔术是从末端掉下来相当于return {};
。在optional
的情况下,这就是nullopt
。如果我读对了我的标准语,对于int
,这是0
,这与从-main
末尾掉下来的行为相匹配。
也有缺点。首先,假设你有一个函数:
int foo(bool condition) {
if (condition) return 7;
custom_abort(); // does not return, but not marked up with `[[noreturn]]`
}
如果编译器不能证明abort
没有返回,这将导致编译器在custom_abort();
之后写入return {};
。这是有代价的(至少是二进制大小)。目前,编译器可以自由排除abort()
之后从foo
返回所需的任何工作,假设abort()
不会返回。
确实,没有任何有效的程序会因这种变化而表现出不同的行为,但以前未定义的行为会被定义,这可能会带来成本。
我们可以用一种稍微不同的方式来处理这个问题:
int foo(bool condition) {
if (condition) return 7;
custom_abort();
this cannot be reached;
}
我们在C++中添加了一个明确的"无法到达此位置"。
添加后,我们可以对不返回的代码路径发出警告,并在以后的标准中强制执行所有代码路径必须断言它们无法到达或必须返回的规则。
在对语言进行这样的转换一两个标准周期后,那么隐含的return {};
将是无害的,除非跳过了标准化的返回阶段。
到目前为止,它是完整的未定义行为。这意味着没有有效的现有代码包含此构造。因此,添加定义良好的行为不会破坏任何有效的代码。至于被破坏的代码,如果你的提议被接受,可能会也可能不会被破坏,但这几乎从来都不是WG21的问题。
主要关注的是它将如何与其他语言功能交互。我认为与constexpr
没有冲突;从CCD_ 22函数的末尾脱落将给出空的CCD_。[[noreturn]]
属性显然毫无意义。[[nodiscard]]
属性影响调用者,而不是实现。例外情况也不受影响。因此,总的来说,这项建议似乎是独立的。
在向WG21提出的建议中,可能值得提出一个不那么激进的替代方案:使普通return;
成为return optional<T>{};
的有效替代方案
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- 什么时候在C++中返回常量引用是个好主意
- 你能重载对象变量名本身返回的内容吗
- 为什么 Serial.println(<char[]>);返回随机字符?
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 如何获取std::result_of函数的返回类型
- QueryWorkingSet总是返回false
- (C++)分析树以计算返回错误值的简单算术表达式
- 访问者访问变体并返回不同类型时出错
- 如何返回一个类的两个对象相加的结果
- OpenInventor从9.8升级到10.4.2后,GLSL纹理返回零
- lower_bound()返回最后一个元素
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- 奇怪的(对我来说)返回声明 - 在谷歌上找不到任何关于它的信息
- 如何取消对nullptr的屏蔽,返回正确的对象
- 奇怪的结构&GCC&clang(void*返回类型)
- 架构决策:返回std::future还是提供回调
- 从python中调用C++函数并获取返回值
- 矩阵向量乘法(cublasDgemv)返回零
- 若控制权到达主体的末尾,那个么返回nullopt会破坏什么