0

我在我的代码中遇到了这种奇怪的无指针情况,现在想知道是否有办法检测它(除了崩溃)。代码设法进入未构造对象的方法。构造b1时,a还没有构造,b尝试使用它。在构建 b2 时,a 已正确构建并且代码按预期工作。

除了显而易见的“不要在你的代码中这样做”之外,我想知道是否有办法在编译或运行时检测到这一点。编译器根本没有检测到它,我只是在程序崩溃时在初始化 DLL 时收到一些关于运行托管代码的晦涩且非常无用的消息。

我尝试测试“this”,但它不是 NULL,因为已分配内存——只是尚未调用构造函数,因此内存处于不确定状态。

我原以为编译器会插入一些调试代码来检测何时发生这种情况,但我想不会。

是否有任何断言或测试或编译时开关我可以用来检测这种情况,或者它只是归结为,“如果它伤害,不要这样做?”

 OUTPUT:
 (NULL)
 test

#include "stdafx.h"
#include "cstring"

class Apple 
{
    char *sometimesinitialized;

    public:
    Apple () { 
        sometimesinitialized = new char[15];
        strcpy_s(sometimesinitialized, 5, "test");
    };
    void test()
    {
        printf("%s\n", sometimesinitialized);
    }
};

class Ball
{
    public:
    Ball();
};

Ball b1; // OOPS!
Apple a;
Ball b2; // Works as expected

Ball::Ball()
{
    a.test();
}

int _tmain(int argc, _TCHAR* argv[])
{
    scanf_s("%i");
    return 0;
}
4

3 回答 3

5

如果一个实例B需要访问一个实例,A那么它应该被传递给B的构造函数。

struct B {
    B(A &a) {
        a.test();
    }
};


A a;
B b(a);
于 2012-08-31T06:06:23.803 回答
2

保证具有静态存储的对象以完全标准保证的方式正确初始化的常见模式如下:

全球.hpp:

struct Foo;
Foo & globalFoo();

全球.cpp:

#include <foo.hpp>

Foo & globalFoo()
{
    static Foo impl;
    return impl;
}

任何需要访问全局Foo对象的人只需调用globalFoo()即可获得引用。该对象在第一次使用之前被初始化,并在程序结束时在所有使用它的人都被销毁后销毁。

于 2012-08-31T08:55:01.230 回答
0

C++ 程序的启动和关闭是两个比较模糊的领域,通常你应该尽量做到你需要的最低限度。

该标准规定,当您执行模块中的任何函数时,编译单元中的所有静态持续时间变量都将被初始化,但是在静态持续时间对象的初始化或销毁期间,静态持续时间对象的状态是什么?或者循环依赖会发生什么。

此外,您不能依赖静态持续时间对象为模块执行例如“服务注册”,因为标准规定编译单元中静态持续时间变量的初始化不需要之前执行,main但可能会延迟到您访问模块中的一个函数;因此,如果对模块的访问取决于模块已注册,则可以简单地跳过初始化,使模块未注册且不可访问。添加这个后期初始化措辞只是为了能够支持语言中的动态库,但事实仍然是标准不强制要求这种技术保证工作。

另一个重要的一点也是关于实施问题。例如,在 Windows 中,我经历过关闭期间的错误可以被简单地忽略(因此应用程序显然正在关闭而没有问题,但实际上它正在因关闭期间的访问冲突而死),并且调试设施在启动之前和之后都无法正常工作的完成main,使得这两个方面的调试问题相当吃力。

例如,考虑使用日志记录工具:如果您想在静态持续时间变量销毁期间调用日志记录并且日志记录本身取决于静态持续时间变量(可能是当您调用日志记录时,日志记录对象已经被销毁)。

此外,不能保证构造和破坏发生的顺序(除了那个短语说在编译单元中调用函数之前,该单元的静态持续时间变量将被初始化)。我经历过,只是在不更改任何内容的情况下重建项目可能会产生不同的序列,这可能是因为智能增量链接技术)。

我的建议是在静态初始化和销毁​​过程中做最少的事情,并避免做任何可能失败的事情。一旦你进入 main 然后按照你想要的顺序显式地做你需要的初始化。以类似的方式,如果您明确控制关闭时发生的事情和顺序,那么您将节省许多调试时间。

过去我是惰性和自动初始化技术的支持者,但由于没有足够的保证,IMO C++ 不是这种方法实用的语言。

于 2012-08-31T06:43:32.973 回答