【问题标题】:Can smart pointer be safer by disallowing automatic variables?智能指针可以通过禁止自动变量更安全吗?
【发布时间】:2021-06-11 05:22:59
【问题描述】:

让我们考虑这样的例子:

#include <memory>

int main() {
    int x = 3;
    std::shared_ptr<int> p{&x};
    //std::shared_ptr<int> p = &x;
}

这个程序有一个双重释放错误(另请参阅:https://godbolt.org/z/T8eh13)。 如果我们用p{&amp;x} 注释掉该行并取消注释它下面的行,编译将失败,这很好,我希望按照https://stackoverflow.com/a/304169/1923988

我的问题是:shared_ptr 是否可以以某种方式实现,以保护我们免受与 p{&amp;x} 类似的用法(通常:获取自动变量地址的用法)?

我想答案是“不,因为被调用者只看到一个指针类型,无论调用者是使用 &amp; 还是真正的指针变量”,但我想知道是否真的存在一些基本限制会阻止编译器区分这两种情况。

【问题讨论】:

  • 编译器可能会发现微不足道的情况(就像您可以发现它并制作测试用例一样)。但是更一般的情况 - 获得已经传递了几次的原始指针的所有权 - 是不可能检查的,第一个(明显的)情况可能不值得努力。 std::make_shared 是创建和拥有共享对象的首选方式,因此在进行代码检查时获取原始指针的所有权是一个危险信号。
  • 将指针传递给自动本地甚至可能在您还提供自定义删除器的情况下是合理的,该删除器执行除释放指针之外的其他操作。所以这最多只能是一个警告。
  • 不是双释放的bug,而是单释放的。
  • 程序员不应该真正拥有现代C++ 代码中随机原始指针 的所有权。原始指针应该被认为是非拥有的,这意味着你应该假设它们指向的对象已经拥有一个拥有者,而不是你。

标签: c++ c++11 reference smart-pointers


【解决方案1】:

即使将局部变量传递给智能指针也是一个有效的用例。

假设您使用的是 C 风格的 OOP API:

struct A { /* ... */ };
void init_a(A* a);
void destroy_a(A* a);

然后:

int main(int argc, char** argv) {
    A a;
    init_a(&a);
    std::unique_ptr<A, void(*)(A*)> a_raii(&a, destroy_a);
}

理论上,编译器应该能够在某些情况下检测到您正在使用指向局部变量的指针构建 stdlib 智能指针,而无需自定义删除器,但这需要相当多的特殊代码来检测C++ 错误的巨大景观。

【讨论】:

  • > 即使将局部变量传递给智能指针也是一个有效的用例。这不会使stackoverflow.com/a/304169/1923988 的答案无效吗?从我的问题措辞可能不清楚,但其中一部分还涉及:为什么一种构建方式会提供保护而另一种则不会?它看起来不一致并且还给出了stackoverflow.com/questions/66612661/… 我想说它应该被命名为shared_unsafe_ptr :)
猜你喜欢
  • 2019-01-27
  • 1970-01-01
  • 2023-04-04
  • 1970-01-01
  • 2012-07-14
  • 1970-01-01
  • 2013-04-16
  • 1970-01-01
相关资源
最近更新 更多