跟踪自动变量寿命?

时间:2008-10-16 22:21:43

标签: c++ scope

这可能是不可能的,但我想我会问......

有没有人可以想到跟踪自动变量是否已被删除而不修改变量本身的类?例如,请考虑以下代码:

const char* pStringBuffer;
{
    std::string sString( "foo" );
    pStringBuffer = sString.c_str();
}

显然,在块之后,pStringBuffer是一个悬空指针,可能有效也可能无效。我想要的是一种包含pStringBuffer(带有const char *的转换运算符)的包装类的方法,但断言它引用的变量仍然有效。通过更改引用变量的类型,我当然可以这样做(例如,提升shared_ptr / weak_ptr),但我希望能够在不对引用类型施加限制的情况下执行此操作。

一些想法:

  • 我可能需要更改赋值语法以包含引用的变量(这很好)
  • 我或许可以查看堆栈指针,以检测我的包装类是否比引用的类“更晚”分配,但这似乎是hacky而不是标准(C ++没有定义堆栈行为)。但它可以奏效。

思考/精彩解决方案?

4 个答案:

答案 0 :(得分:1)

一般来说,在C ++中根本不可能,因为指针太“原始”。另外,查看您是否在引用的类之后分配是不行的,因为如果更改字符串,则c_str指针可能会发生变化。

在这种特殊情况下,您可以检查字符串是否仍然为c_str返回相同的值。如果是,您可能仍然有效,如果不是,那么您的指针无效。

作为一个调试工具,我建议使用高级内存跟踪系统,比如valgrind(我只担心linux可用。对于windows存在类似的程序,但我相信它们都要花钱。这个程序是我唯一的原因在我的mac上安装了linux)。以程序执行速度慢得多为代价,valgrind会检测您是否读过无效指针。虽然它并不完美,但我发现它可以检测到许多错误,特别是这类错误。

答案 1 :(得分:0)

您可能会发现一种有用的技术是将new / delete运算符替换为您自己的实现,这些运算符将使用的内存页(由operator new分配)标记为不可访问的已释放(由operator delete解除分配)。您需要确保永远不会重复使用内存页面,因此由于内存耗尽会对运行时长度产生限制。

如果您的应用程序在取消分配后访问内存页面(如上例所示),操作系统将捕获尝试访问并引发错误。它本身并不完全跟踪,因为应用程序将立即停止,但它确实提供了反馈: - )

此技术适用于狭窄的场景,不会捕获所有类型的内存滥用,但它可能很有用。希望有所帮助。

答案 2 :(得分:0)

你可以创建一个包装类,它在你提到的简单情况下工作。也许是这样的:

X<const char*> pStringBuffer;
{
    std::string sString( "foo" );
    Trick trick(pStringBuffer).set(sString.c_str());
} // trick goes out of scope; its destructor marks pStringBuffer as invalid

但它无助于更复杂的案例:

X<const char*> pStringBuffer;
{
    std::string sString( "foo" );
    {
        Trick trick(pStringBuffer).set(sString.c_str());
    } // trick goes out of scope; its destructor marks pStringBuffer as invalid
}

此处,失效发生得太快。

大多数情况下,您应该编写尽可能安全的代码(请参阅:智能指针),但不要更安全(请参阅:性能,低级接口),并使用工具(valgrind,Purify)确保没有任何漏洞裂缝。

答案 3 :(得分:0)

鉴于“pStringBuffer”是sString超出范围后您的示例中唯一存在的部分,您需要对其进行一些更改或替代,以反映这一点。一种简单的机制是一种范围保护,范围匹配sString,当它被销毁时会影响pStringBuffer。例如,它可以将pStringBuffer设置为NULL。

要做到这一点而不改变“变量”的类只能在很多方面完成:

  • 在与sString相同的范围内引入一个独特的变量(为了减少冗长,您可以考虑使用宏来一起生成两个东西)。不太好。

  • 用模板包裹ala X sString:这是否可以“修改变量的类型”......另一种观点是sString成为同一变量的包装器。它也会受到影响,你可以做的最好的事情是将包装的构造函数的模板化构造函数传递参数赋予一些有限的N个参数。

这些都没有多大帮助,因为他们依赖开发人员记住使用它们。

很多 更好的方法是将“const char * pStringBuffer”简单地设为“std :: string some_meaningful_name”,并根据需要分配给它。鉴于参考计数,它在99.99%的时间内并不太昂贵。