【问题标题】:Possible to detect stack allocated object that isn't captured?可以检测未捕获的堆栈分配对象吗?
【发布时间】:2023-03-19 03:16:02
【问题描述】:

是否有可能以任何方式(静态分析)防止或检测以下错误,其中堆栈分配的对象未被捕获并超出构造它的同一行的范围?

Resource  resourceA, resourceB;

void someFunction()
{
    ScopedResourceBinder resourceBindA( resourceA );
    ScopedResourceBinder( resourceB ); // <--- BUG
}

第一个ScopedResourceBinder 是正确的,但第二个没有做任何事情,因为它在“绑定”之后立即“解除绑定”(假设是这样)。

这显然是程序员的错误,但我现在已经调试了几次(几次都调试了几个小时),而且很难发现。一旦你看到它,你会认为“啊,那是一个愚蠢的”,但在实践中,很容易犯错误,编译器毫无防备......或者是吗?

背景信息:我使用的库大量使用 RAII 类来推送弹出状态,例如 OpenGL 资源。使用作用域管理绑定是手动调用 bind() / unbind() 函数的一大改进,但这里列出的潜在错误来自这种新模式。

【问题讨论】:

标签: c++ raii


【解决方案1】:

ScopedResourceBinder( resourceB );ScopedResourceBinder resourceB;相同,即声明了一个名为resourceB的命名变量,调用了ScopedResourceBinder的默认构造函数。

这会一直持续到函数结束,但它仍然是一个错误,因为它没有执行您绑定到变量resourceB 的意图。

为了防止这种特殊情况,您可以确保ScopedResourceBinder 没有默认构造函数。

【讨论】:

  • 事实上,它从不绑定,因为它是默认构造的。
  • 对,它仍然是一个错误(尽管与 OP 所想的完全不同!)
  • 这指出了一种避免它的方法——确保你的作用域锁类对象没有默认构造函数。
【解决方案2】:

在一般的编码实践中,我们应该在类定义本身中明确表达我们的意图。

例如:

如果我们想要单例类,那么所有的构造函数都应该是私有的。

如果我们要构造一个带有一些变量的对象,那么只有需要的构造函数应该被公开,其余的都应该被提到为私有的。

通过这种方式,我们将能够仅在编译期间标记所有错误用法。

【讨论】:

    猜你喜欢
    • 2014-03-04
    • 2018-09-09
    • 2013-01-25
    • 2014-06-10
    • 1970-01-01
    • 2015-01-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多