编码风格绝对可以保证没有内存泄漏吗?

时间:2015-08-13 17:05:22

标签: c++ memory-leaks coding-style c++14

从不使用

new
delete
release

并且更喜欢使用

std::make_unique
std::unique_ptr
std::move
reset(多余的)

应该道德导致没有内存泄漏:新的指针只能在智能指针中创建,从而无法逃脱,因为我们不允许使用release

因此,人们可能会尝试使用这种编码风格,然后再也不用费心去检查内存泄漏 - 无论可能抛出异常,智能指针的RAII语义应该始终清理任何悬空指针作为堆栈解开了。

除了C ++充满了令人讨厌的惊喜。根据我的假设反复粉碎的经验,我无法帮助,但我认为可能会有一些角落案件无论如何都会导致内存泄漏。更糟糕的是,可能有一种明显的方式来释放指针的所有权而不是release本身。或者另一个智能指针类没有一个explicit构造函数,它可能会意外地摄取通过get获得的原始指针,导致双重释放......

有漏洞吗?如果有,可以通过添加一些更简单的限制来修复它们吗? (不分配任何内存都不算数!)如果可以达到一套防止所有类型内存错误的编码指南,那么完全忘记内存管理的细节是否可以?

4 个答案:

答案 0 :(得分:5)

struct evil {
  std::shared_ptr<evil> p;
};
void foo() {
  auto e = std::make_shared<evil>();
  e->p = e;
}
int main() {
  for (unsigned i = 1; i != 0; ++i) {
    foo();
    if (i % 100000000)
      std::cout << "I leak\n";
  }
}

上述程序遵守您的限制,并像筛子一样泄漏。

最重要的是,未定义的行为可能会导致泄漏。

答案 1 :(得分:4)

我认为循环引用只是std::shared_ptr ...

的问题
struct X
{
    std::unique_ptr<X> x;
};

void leak()
{
    auto x = std::make_unique<X>();
    x->x = std::move(x);
}

这可以通过确保在AB之间添加边缘而形成的类型的图表中没有周期来解决,当且仅当A包含成员{{ 1}}其中std::unique_ptr<C>C的基础。

答案 2 :(得分:1)

  

可以完全忘记内存管理的细节吗?

我认为在可预见的未来,编程的答案将是 no 。即使在今天的垃圾收集语言中,如果您需要高性能应用程序,也不能忘记内存管理的细节。

当程序意外挂起不再需要的引用时,垃圾收集语言中仍会发生内存泄漏。遵循上面针对C ++制定的规则仍然会出现相同的问题,甚至更有可能成为使用shared_ptr的问题。此类型的常见错误依赖于容器中的对象,或者通过垃圾收集语言中的托管引用的观察者或C ++中的shared_ptr

答案 3 :(得分:1)

没有保证,有太多人可以搞砸......

  • 工会...... (Example)

    union Devil {
      std::unique_ptr<int> ptr;
      int b;
      Devil () {}
      ~Devil () {
        // no idea what I'm doing
      }
    };
    
  • 继承...... (Example)

    struct Base {};
    struct Derived : public Derived {
     std::unique_ptr<int> ptr;
    };
    // later ...
    std::unique_ptr<Base> p = std::make_unique<Derived>(42);
    // oops
    
  • 在筹码上玩......

    int f1[10];
    std::unique_ptr<int> p[2];
    int f2[10];
    // later ...
    p[2] = std:: make_unique<int>(42);
    // oops
    

...或更普遍的未定义行为。以上几点肯定只是冰山一角......

相关问题