C++17 编译器不应该发现对未定义值的传递引用吗?
Posted
技术标签:
【中文标题】C++17 编译器不应该发现对未定义值的传递引用吗?【英文标题】:C++17 Shouldn't compilers be spotting pass-by-reference to undefined values? 【发布时间】:2018-09-19 13:15:07 【问题描述】:在为项目制作小型解析器时,我不断收到分段错误...追踪到换位错字。
此代码示例不是原始代码,而是重现了错误。
我很惊讶我的编译器都没有发现引用未初始化。
GCC 和 Clang 似乎都可以在没有警告或错误的情况下编译它。
他们不应该将 REFERENCE TO v2 标记为未初始化吗?
我对 C++ 比较陌生,并且正在学习 C++17/20。 但我很好奇为什么在这种情况下,编译器没有发现 v2 是未定义的,而是传递了对未定义对象的引用。
#include <iostream>
#include <vector>
struct A
using vectorA = std::vector<A>;
int foo;
vectorA vA;
A() = delete; // Implicit but let's be certain!
A(int f) noexcept
: foo f,
vA
;
A::vectorA& recurse(A::vectorA& head, int tail) noexcept
head.emplace_back(tail); return head;
int main()
// A tree of A's
A::vectorA v1 ;
// Fill it using recursive fn converting bars into foos,
// a bar at a time
int bar 666;
A::vectorA v2 recurse(v2, bar);
// ^
// typo of 'v2' instead of 'v1' still compiles!
// SHOULD, of course, read; A::vector_of_A v2 recurse(v1, bar);
//
// But v2 is... what exactly? At the point it is passed to recurse?
// It is uninitialized although it has an address and (likely) space
// allocated to hold it.
// No warning?
std::cout << "Should this compile?\n";
std::cout << "Oops! Segmentation Fault Guaranteed!\n";
【问题讨论】:
相关Is passing a C++ object into its own constructor legal?和Has C++ standard changed with respect to the use of indeterminate values and undefined behavior in C++14? 标准规定,即使在值初始化之前,对值的引用也是有效的。同样,指向它的指针也是有效的。只有在定义之前通过引用访问变量是无效的。例如,存储参考以供以后使用是有效的操作。 您对编译器的期望很高。它必须检查recurse
,看看将v2
提供给它是否有效,如果不是,则警告您。编译器不会完成所有这些工作。语法是正确的,所以它会继续下去。
@DavidHParry 但是v2
是参数head
的一个完全有效的参数。如果 recurse
是例如输出&head
而不是访问head
的成员,一切都会好起来的。
如果您使用“几乎总是自动”的约定,那么这个auto v2 = A::vectorA recurse(v2, bar);
将无法编译。不是每个人都喜欢这种风格,所以这取决于你团队的德鲁特人或你自己的风格敏感性。
【参考方案1】:
如果这不能编译,那么也不能执行以下操作,这并不少见:
struct base
int& x;
base(int& x) : x(x)
;
struct foo : base
int x;
foo() : base(x)
;
在调用base
构造函数时,x
尚未初始化,但存储对它的引用以供以后使用是完全有效的。
这只是一个示例,其中获取对尚未初始化的对象的引用就可以了,禁止这样做将需要编写非常不清楚的繁琐代码。
【讨论】:
这只是一个代码 sn-p,它重现了使用 CompilerExplorer 产生的错误,而不是产生错误的代码......你需要 20MB 的空间...... @DavidHParry 抱歉,我没有收到您的评论。我没有在我的回答中引用您的代码......“不是导致错误的代码”?我们只能讨论我们在这里看到的东西,而不是只有您拥有的东西,如果您的示例与您的真实代码有很大不同,您应该编辑示例 导致错误的故障如上所述。您不需要原始代码来理解问题。原来的变量名比本例中使用的更具指导性? @DavidHParray 仍然不明白你想告诉我什么。据我了解,您问是否应该禁止传递统一引用的问题,我给您举了一个例子,这样做是完全可以的,而禁止这样做会非常糟糕。这与“出错需要 20MB”有什么关系? @DavidHParry 如果您对我对变量名的批评感到不安,为什么不更改它们?无论如何,如果这让你感觉更好,我会删除 PS:P以上是关于C++17 编译器不应该发现对未定义值的传递引用吗?的主要内容,如果未能解决你的问题,请参考以下文章
c# - 我应该使用“ref”通过引用方法来传递集合(例如列表)吗?