Visual Studio 2008 下的虚假C++析构函数调用(在 GCC 下不存在)
Spurious C++ destructor call under Visual Studio 2008 (absent under GCC)
采用以下(人为的(类层次结构,该层次结构从构造函数和析构函数打印到控制台:
#include <iostream>
class A {
public:
A() { std::cout << "A"; }
~A() { std::cout << "~A"; }
};
class B : public A {
public:
B() { std::cout << "B"; }
~B() { std::cout << "~B"; }
};
void func(A a) { }
int main() {
B b;
func(b);
std::cout << "X";
return 0;
}
在 linux 下使用 gcc 编译,它按预期打印AB~AX~B~A
(X
之前打印的~A
是按值传递到 func
的结果,这会创建一个副本,该副本在函数返回时被销毁(。
但是在带有VS2008的Windows下编译它打印AB~A~AX~B~A
- 额外的~A
从何而来?如果A(A& that) {};
显式定义了复制 xtor,或者析构函数被声明为虚拟(可以说应该是这样(,它就会消失。
注释表明 MSVC 2008 使用 g++ 不使用的临时来传递参数。如果是这样,这是一个错误。从 C++03 [dcl.init]/12
:在参数传递、函数返回、引发异常 (15.1(、处理异常 (15.3( 和大括号括起来的初始值设定项列表 (8.5.1( 中发生的初始化称为复制初始化,等效于
T x = a;
现在这是关键的一点。 在T x = a;
中,如果a
不是T
或派生自T
,则等价于T x = T(a);
,并且在概念上使用了额外的临时。(此临时人员有资格复制省略(。
但是,如果a
是T
或派生自T
,则不得有额外的临时。它与T x(a);
相同。
在这个问题的代码中,既然B
派生自A
,就不能有临时的。
C++03 中的支持文本位于 [dcl.init]/14 下(我突出显示了与此问题的代码示例相关的部分(:
如果目标类型是(可能符合 cv 条件的(类类型:
- 如果类是聚合 (8.5.1(,并且初始值设定项是大括号括起来的列表,请参阅 8.5.1。
- 如果初始化是直接初始化,或者如果是复制初始化,其中源类型的 cv 非限定版本与目标类的类相同,或者是目标类的派生类,则考虑构造函数。枚举适用的构造函数 (13.3.1.3(,并通过重载解析 (13.3( 选择最佳构造函数。调用这样选择的构造函数来初始化对象,并将初始值设定项表达式作为其参数。如果未应用构造函数,或者重载解析不明确,则初始化格式不正确。
- 否则(即,对于剩余的复制初始化情况(,如 13.3.1.4 中所述枚举可以从源类型转换为目标类型或(使用转换函数时(转换为其派生类的用户定义的转换序列,并通过重载分辨率 (13.3( 选择最佳转换序列。如果转换无法完成或不明确,则初始化格式不正确。使用初始值设定项表达式作为其参数调用所选函数;如果函数是构造函数,则调用将初始化目标类型的临时函数。然后,调用的结果(构造函数情况的临时结果(用于根据上述规则直接初始化作为复制初始化目标的对象。在某些情况下,一个 允许通过将中间结果直接构造到正在初始化的对象中来消除这种直接初始化中固有的复制;参见 12.2、12.8。
相关文章:
- 函数调用中参数的顺序重要吗
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 变量没有改变?通过向量的函数调用
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 是否有C++编译器选项允许激进地删除所有函数调用,并将参数传递给具有空体的函数
- 我知道函数调用中存在歧义.有没有办法调用foo()函数
- 为什么这个自定义分配器的析构函数在 GCC/MSVS 的 stdlib 中被调用两次
- `noexcept`函数中的std :: terminate`调用函数有限-GCC vs clang codegen
- GCC 9.1 返回 void& 作为显式析构函数调用的结果类型。这是一个错误吗?
- 为什么 gcc 不能去虚拟化这个函数调用?
- 从 C 代码链接错误调用C++函数(使用 gcc 进行链接)
- 为什么它是一个使用GCC的令人震惊的函数调用?模板扣减失败
- 使用gcc进行纯虚拟函数调用时发生链接器错误
- Clang和GCC在定义之前对函数调用的诊断行为不同
- Gcc x64函数调用
- gcc是否会优化对相同变量的重复函数调用,并为每次调用提供相同的输出?
- 如何消除GCC c++中函数调用的歧义
- gcc-gprof/gcov/other-如何获取函数调用/出口+控制流语句的序列
- Visual Studio 2008 下的虚假C++析构函数调用(在 GCC 下不存在)
- GCC 问题 - 没有匹配的函数调用