使用未初始化的变量是未定义的行为吗?
Is the use of an uninitialized variable undefined behavior?
我不知道“未定义行为”在 Perl 中是否意味着什么,但我想知道在 Perl 中使用未初始化的变量是否会引发不良行为。
让我们考虑以下脚本:
use strict;
use warnings FATAL => 'all';
use P4;
my $P4;
sub get {
return $P4 if $P4;
# ...connection to Perforce server and initialization of $P4 with a P4 object...
return $P4;
}
sub disconnect {
$P4 = $P4->Disconnect() if $P4;
}
sub getFixes {
my $change = shift;
my $p4 = get();
return $p4->Run( "fixes", "-c", $change );
}
这里,变量$P4
,用于在连接到Perforce 服务器后存储一个P4 对象,并没有在脚本的开头进行初始化。但是,无论先调用哪个函数(get
、disconnect
或getFixes
),变量都会在使用前进行初始化。
这样做有风险吗?我应该在脚本开头显式初始化 $P4
变量吗?
用 my
声明的变量用 undef
初始化。这里没有未定义的行为。
这在 perldoc persub
中有记录:
If no initializer is given for a particular variable, it is created with the undefined value.
然而,奇怪的结构 my $x if $condition
确实有未定义的行为。永远不要那样做。
my
将标量初始化为 undef
,并将数组和散列初始化为空。
您的代码很好,但我会采用不同的销毁方法。
方案一:通过包装提供析构函数
use Object::Destroyer qw( );
use P4 qw( );
my $P4;
sub get {
return $P4 ||= do {
my $p4 = P4->new();
$p4->SetClient(...);
$p4->SetPort(...);
$p4->SetPassword(...);
$p4->Connect()
or die("Failed to connect to Perforce Server" );
Object::Destroyer->new($p4, 'Disconnect')
};
}
# No disconnect sub
选项 2:通过 monkey-patching 提供析构函数
use P4 qw( );
BEGIN {
my $old_DESTROY = P4->can('DESTROY');
my $new_DESTROY = sub {
my $self = shift;
$self->Disconnect();
$old_DESTROY->($self) if $old_DESTROY;
};
no warnings qw( redefined );
*P4::DESTROY = $new_DESTROY;
}
my $P4;
sub get {
return $P4 ||= do {
my $p4 = P4->new();
$p4->SetClient(...);
$p4->SetPort(...);
$p4->SetPassword(...);
$p4->Connect()
or die("Failed to connect to Perforce Server" );
$p4
};
}
# No disconnect sub
只回答了几个 straight-up 基本问题的答案。
if "undefined behavior" means something in Perl
是的,在 Perl 中有这样的概念,并且文档对此进行了警告(比 C
中的频率低得多)。请参阅脚注 † 中的一些示例。另一方面,在文档的许多地方,人们会发现以
结尾的讨论
... So don't do that.
它经常出现会使解释器感到困惑,并可能导致奇怪且可能无法预测的行为。这些有时是典型的“未定义行为”,即使它们没有直接这样调用。
主要问题是未初始化的变量如何关联,根据标题和
if using not initialized variables in Perl may provoke unwanted behaviors
这通常不会导致“未定义的行为”,但它当然可能会导致麻烦,而且大多数情况下都会收到警告。当然,除非变量在这种“使用”中被合法地初始化。例如,
my $x;
my $z = $x + 3;
会针对使用 $x
而不是 $z
发出警告(如果 warnings
开启!)。请注意,这仍然会成功,因为 $x
被初始化为 0
。 (但是在问题中显示的内容中,由于 FATAL
,代码将在此时中止。)
从这个意义上说,问题中显示的代码似乎很好,因为正如您所说
the variable will be initialized before being used
针对未初始化变量的真值测试很好,因为一旦它被声明它就配备了值 undef
,在此类测试中是可接受的(和假的)。
请参阅 Declarations in perlsyn 中的前几段,了解关于何时需要或不需要变量的摘要 defined
。
† 文档中特别标记为“未定义”的一些行为列表
在标量上下文中调用 sort
In list context, this sorts the LIST and returns the sorted list value. In scalar context, the behaviour of sort is undefined.
长度太大 truncate
The behavior is undefined if LENGTH is greater than the length of the file.
使用不兼容(无意义)的 sysopen 标志
The behavior of O_TRUNC
with O_RDONLY
is undefined.
用kill向process-list发送信号,其中可以使用负信号或进程号发送到进程组
If both the SIGNAL and the PROCESS are negative, the results are undefined. A warning may be produced in a future version.
来自 Auto-increment and Auto-decrement (perlop)
... modifying a variable twice in the same statement will lead to undefined behavior.
迭代each,尽管它可能很棘手,但如果将哈希插入到
中则表现不佳
If you add or delete a hash's elements while iterating over it, the effect on the iterator is unspecified; for example, entries may be skipped or duplicated--so don't do that. It is always safe to delete the item most recently returned by each
, ...
这会引发运行时警告 (F),described in perldiag
Use of each()
on hash after insertion without resetting hash iterator results in undefined behavior.
Statement modifier (perlsyn) 用于 my
The behaviour of a my
, state
, or our
modified with a statement modifier conditional or loop construct (for example, my $x if ...
) is undefined.
考虑到 UB 的含义,其中一些似乎有点平淡无奇(可以预见)。感谢 ikegami 的评论。此列表的一部分可在 this question.
中找到
从发帖时的最新文档 (v5.32.1) 中窥探
我不知道“未定义行为”在 Perl 中是否意味着什么,但我想知道在 Perl 中使用未初始化的变量是否会引发不良行为。
让我们考虑以下脚本:
use strict;
use warnings FATAL => 'all';
use P4;
my $P4;
sub get {
return $P4 if $P4;
# ...connection to Perforce server and initialization of $P4 with a P4 object...
return $P4;
}
sub disconnect {
$P4 = $P4->Disconnect() if $P4;
}
sub getFixes {
my $change = shift;
my $p4 = get();
return $p4->Run( "fixes", "-c", $change );
}
这里,变量$P4
,用于在连接到Perforce 服务器后存储一个P4 对象,并没有在脚本的开头进行初始化。但是,无论先调用哪个函数(get
、disconnect
或getFixes
),变量都会在使用前进行初始化。
这样做有风险吗?我应该在脚本开头显式初始化 $P4
变量吗?
用 my
声明的变量用 undef
初始化。这里没有未定义的行为。
这在 perldoc persub
中有记录:
If no initializer is given for a particular variable, it is created with the undefined value.
然而,奇怪的结构 my $x if $condition
确实有未定义的行为。永远不要那样做。
my
将标量初始化为 undef
,并将数组和散列初始化为空。
您的代码很好,但我会采用不同的销毁方法。
方案一:通过包装提供析构函数
use Object::Destroyer qw( );
use P4 qw( );
my $P4;
sub get {
return $P4 ||= do {
my $p4 = P4->new();
$p4->SetClient(...);
$p4->SetPort(...);
$p4->SetPassword(...);
$p4->Connect()
or die("Failed to connect to Perforce Server" );
Object::Destroyer->new($p4, 'Disconnect')
};
}
# No disconnect sub
选项 2:通过 monkey-patching 提供析构函数
use P4 qw( );
BEGIN {
my $old_DESTROY = P4->can('DESTROY');
my $new_DESTROY = sub {
my $self = shift;
$self->Disconnect();
$old_DESTROY->($self) if $old_DESTROY;
};
no warnings qw( redefined );
*P4::DESTROY = $new_DESTROY;
}
my $P4;
sub get {
return $P4 ||= do {
my $p4 = P4->new();
$p4->SetClient(...);
$p4->SetPort(...);
$p4->SetPassword(...);
$p4->Connect()
or die("Failed to connect to Perforce Server" );
$p4
};
}
# No disconnect sub
只回答了几个 straight-up 基本问题的答案。
if "undefined behavior" means something in Perl
是的,在 Perl 中有这样的概念,并且文档对此进行了警告(比 C
中的频率低得多)。请参阅脚注 † 中的一些示例。另一方面,在文档的许多地方,人们会发现以
... So don't do that.
它经常出现会使解释器感到困惑,并可能导致奇怪且可能无法预测的行为。这些有时是典型的“未定义行为”,即使它们没有直接这样调用。
主要问题是未初始化的变量如何关联,根据标题和
if using not initialized variables in Perl may provoke unwanted behaviors
这通常不会导致“未定义的行为”,但它当然可能会导致麻烦,而且大多数情况下都会收到警告。当然,除非变量在这种“使用”中被合法地初始化。例如,
my $x;
my $z = $x + 3;
会针对使用 $x
而不是 $z
发出警告(如果 warnings
开启!)。请注意,这仍然会成功,因为 $x
被初始化为 0
。 (但是在问题中显示的内容中,由于 FATAL
,代码将在此时中止。)
从这个意义上说,问题中显示的代码似乎很好,因为正如您所说
the variable will be initialized before being used
针对未初始化变量的真值测试很好,因为一旦它被声明它就配备了值 undef
,在此类测试中是可接受的(和假的)。
请参阅 Declarations in perlsyn 中的前几段,了解关于何时需要或不需要变量的摘要 defined
。
† 文档中特别标记为“未定义”的一些行为列表
在标量上下文中调用 sort
In list context, this sorts the LIST and returns the sorted list value. In scalar context, the behaviour of sort is undefined.
长度太大 truncate
The behavior is undefined if LENGTH is greater than the length of the file.
使用不兼容(无意义)的 sysopen 标志
The behavior of
O_TRUNC
withO_RDONLY
is undefined.用kill向process-list发送信号,其中可以使用负信号或进程号发送到进程组
If both the SIGNAL and the PROCESS are negative, the results are undefined. A warning may be produced in a future version.
来自 Auto-increment and Auto-decrement (perlop)
... modifying a variable twice in the same statement will lead to undefined behavior.
迭代each,尽管它可能很棘手,但如果将哈希插入到
中则表现不佳If you add or delete a hash's elements while iterating over it, the effect on the iterator is unspecified; for example, entries may be skipped or duplicated--so don't do that. It is always safe to delete the item most recently returned by
each
, ...这会引发运行时警告 (F),described in perldiag
Use of
each()
on hash after insertion without resetting hash iterator results in undefined behavior.Statement modifier (perlsyn) 用于
my
The behaviour of a
my
,state
, orour
modified with a statement modifier conditional or loop construct (for example,my $x if ...
) is undefined.
考虑到 UB 的含义,其中一些似乎有点平淡无奇(可以预见)。感谢 ikegami 的评论。此列表的一部分可在 this question.
中找到从发帖时的最新文档 (v5.32.1) 中窥探