5

无法理解奇怪的程序行为 - 希望有人可以解释。

假人.h:

#ifndef DUMMY_H
#define DUMMY_H

#include <iostream>

class Dummy
{
    int val;

public:
    int Init(int new_val)
    {
        return val = new_val;
    }

    int Get()
    {
        return val;
    }

    Dummy():
        val(-1)
    {
        std::cout << "constructed" << std::endl;
    }

    ~Dummy()
    {
        std::cout << "deconstructed" << std::endl;
    }
};

#endif /*DUMMY_H*/

标头.h:

#include "dummy.h"

extern Dummy dummy;

虚拟.cpp:

#include "dummy.h"

Dummy dummy;

主.cpp:

#include <iostream>

#include "header.h"

int res1 = dummy.Init(2);
int res2 = dummy.Get();

int main()
{
    std::cout << res1 << std::endl;
    std::cout << res2 << std::endl;
    std::cout << dummy.Get() << std::endl;

    return 0;
}

编译:g++ -Wall -Wextra main.cpp dummy.cpp

输出:

constructed
2
2
-1
deconstructed

为什么在 main() 函数中调用的第二个 Get() 返回 -1?为什么分配的值​​从虚拟实例中消失并且没有调用解构函数。它如何变成-1?

upd:向 Init() 和 Get() 添加了调试信息:

新输出:

init
get
constructed
2
2
get
-1
deconstructed

upd2:有趣的事实 - 在一个可执行文件中单独编译和链接目标文件改变了情况:

g++ -c dummy.cpp 
g++ -c main.cpp 
g++ dummy.o main.o 

./a.out

constructed
init
get
2
2
get
2
deconstructed

但这是一个陷阱!

4

2 回答 2

10

未指定不同翻译单元中全局变量的初始化顺序。可以先构造 main.cpp 中的一个dummy或两个 global 。int

在您的情况下,它res1首先res2被初始化,因此您通过调用尚未构造的对象上的成员函数来调用未定义的行为。

要修复它,请尝试以下操作:

标头.h:

#include "dummy.h"

Dummy& getDummy();

虚拟.cpp:

#include "dummy.h"

Dummy& getDummy()
{
    static Dummy dummy; // gets initialized at first call
                        // and persists for the duration of the program
    return dummy;
}

主文件

int res1 = getDummy().Init(2);
int res2 = getDummy().Get();

如果它有助于理解,也可以在Getand中添加一些调试 cout 语句Init。您所经历的也称为静态初始化命令惨败

于 2013-09-18T11:32:22.643 回答
4

所以,发生的事情是int res1 = dummy.Init(2);在初始化int res2 = dummy.Get();之前运行。dummy然后, beforemain被输入,dummy被构造并具有-1存储在val.

在这种特殊情况下,对于此版本的编译器,您可以通过将目标文件重新排列为g++ -o myprog dummy.o main.o而不是g++ -o myprog main.o dummy.o- 来更改这一点,但这并不能保证解决问题,并且在未来版本的编译器/链接器中,结果可能很好再次改变。C++ 标准根本不提供任何保证——我只是从我个人所见的情况中建议“顺序可能很重要”。而且由于对这些东西没有特殊要求,因此允许编译器供应商随时以他们喜欢的任何方式对其进行更改。

于 2013-09-18T11:41:35.040 回答