C++ 将非构造函数参数变量从派生类传递给基类构造函数会导致奇怪的行为

C++ 将非构造函数参数变量从派生类传递给基类构造函数会导致奇怪的行为,c++,C++,我有下面的代码,这是我以前在另一个项目中遇到的一个问题的简化,它表现出奇怪的行为 class A { public: A() : x(12) {} private: int x; }; class Base { public: Base(A& a) : a(a) {} protected: A a; }; int main() { A a{}; class Derived : public Base { public: Der

我有下面的代码,这是我以前在另一个项目中遇到的一个问题的简化,它表现出奇怪的行为

class A
{
public:
  A()
    : x(12) {}
private:
  int x;
};

class Base
{
public:
  Base(A& a)
    : a(a) {}
protected:
  A a;
};

int main()
{
  A a{};

  class Derived : public Base
  {
  public:
    Derived()
      : Base(a) {}
  };

  Derived d{};

  return 0;
}
这段代码编译成功。假设此代码位于名为
mre.cpp
的文件中,我使用GCC 9.2和以下命令编译了它:

g++ -g mre.cpp -o mre
乍一看,人们可能会认为一切都如预期的那样。值得注意的是,忽略访问修饰符,
d.a.x
应该等于
12
。为了确认,让我们跳到GDB并在
return0
所在的行上设置一个断点

我们先来看看
a
。我们可以通过运行:

(gdb) p a
$2 = {x = 12}
我们可以合理地预期,
d.a.x
将等于
12
。不幸的是,当我们执行以下操作时:

(gdb) p d
$1 = {<Base> = {a = {x = 32767}}, <No data fields>}

通过将
派生的
构造函数更改为

Derived(A& a)
  : Base(a) {}

并在初始化
d
期间将
a
作为构造函数参数传递,即
派生的d{a}
派生的
类构造函数中传递
a

Derived()
  : Base(a) {}
是基类中的成员变量
a
,而不是
main
中的局部变量

派生的
类构造函数更改为

Derived( A& a )
  : Base(a) {}
此新函数参数
a
隐藏成员变量

要进一步了解情况,请尝试重命名局部变量
a

e、 g


这应该告诉您,不允许在封闭函数中引用局部变量。

派生的
类构造函数中的
a

Derived()
  : Base(a) {}
是基类中的成员变量
a
,而不是
main
中的局部变量

派生的
类构造函数更改为

Derived( A& a )
  : Base(a) {}
此新函数参数
a
隐藏成员变量

要进一步了解情况,请尝试重命名局部变量
a

e、 g


这应该告诉您不允许在封闭函数中引用局部变量。

请提供一个自包含的测试用例(或)来说明您的问题。这包括您的构建步骤、执行步骤,以及您传递给gdb的确切命令。这可能是静态初始化顺序失败的一种情况,但从提供的信息片段中无法分辨!e、 g.我们甚至不知道您在任何情况下如何实例化
测试系统
,或者在何处、何时、使用什么参数。
系统
组件管理器0
是全局对象吗?@seanfrancis.balais您需要提供完整的。为了理解发布的代码,有很多漏洞需要填补。这使得找到你不可避免地在某处拥有的UB变得不可能。有些事情是不符合逻辑的:您有
componentManager0
componentManager
。它们应该是一样的吗?如果不是,组件管理器是否是全局的?你是说
TestSystem
是一个本地类吗?如何定义组件管理器?如何定义
系统
等的所有使用功能?您确定其中任何一个都没有缓冲区溢出吗?等等,没问题。对于未来的ref,MRE要求不仅仅是保持站点干净/可重复使用,并使问题易于回答(尽管这是其中的一个重要部分)-如果你养成了提前准备的习惯,你通常会在过程中发现错误。这是一项宝贵的调试技能。请提供一个自包含的测试用例(或)来演示您的问题。这包括您的构建步骤、执行步骤,以及您传递给gdb的确切命令。这可能是静态初始化顺序失败的一种情况,但从提供的信息片段中无法分辨!e、 g.我们甚至不知道您在任何情况下如何实例化
测试系统
,或者在何处、何时、使用什么参数。
系统
组件管理器0
是全局对象吗?@seanfrancis.balais您需要提供完整的。为了理解发布的代码,有很多漏洞需要填补。这使得找到你不可避免地在某处拥有的UB变得不可能。有些事情是不符合逻辑的:您有
componentManager0
componentManager
。它们应该是一样的吗?如果不是,组件管理器是否是全局的?你是说
TestSystem
是一个本地类吗?如何定义组件管理器?如何定义
系统
等的所有使用功能?您确定其中任何一个都没有缓冲区溢出吗?等等,没问题。对于未来的ref,MRE要求不仅仅是保持站点干净/可重复使用,并使问题易于回答(尽管这是其中的一个重要部分)-如果你养成了提前准备的习惯,你通常会在过程中发现错误。这是一项宝贵的调试技能。即使是
-Wextra
也不认为这段代码有潜在的问题,这让我有点(但不是完全)惊讶。并不是说OP正在使用警告标志;)我在生成MRE后意识到了这一点,但我没有立即将实现作为问题的一部分来编写。哈哈。不过,谢谢!即使是
-Wextra
也不认为这段代码有潜在的问题,这让我有点(但不是完全)惊讶。并不是说OP正在使用警告标志;)我在生成MRE后意识到了这一点,但我没有立即将实现作为问题的一部分来编写。哈哈。不过,谢谢!