首页 > 解决方案 > 在全局容器中存储局部变量的内存地址

问题描述

在我的理解中,不可能将局部内存的地址存储在全局容器中,因为局部变量最终会被销毁。

class AA {
  std::string name;
public:
  explicit AA(std::string n) : name(n) {}
  std::string getName() const {
    return name;
  }
};

class Y {
  std::vector<std::reference_wrapper<AA>> x;
public:
  void addAA(AA& aa) {
    x.emplace_back(aa);
  }
  AA& getLastA() {
    return x.back();
  }
};

void foobar(Y& y) {
  AA aa("aa");
  y.addAA(aa);
}

int main() {

  Y y;
  foobar(y);
  std::cout << y.getLastA().getName() << std::endl; // error - probably because the local aa has been destroyed.
  return 0;
}

但是,我不明白为什么这段代码有效:

void foobar(Y& y, AA& aa) {
  y.addAA(aa);
}

int main() {

  Y y;
  {
    AA aa("aa");
    foobar(y,aa);
  }


  std::cout << y.getLastA().getName() << std::endl;
  return 0;
}

aa再次在另一个范围内创建,应该被销毁。但是,它可以在稍后获得它的名字main。代码工作正常。

为什么我们不会在第二种情况下得到错误?

标签: c++

解决方案


Rust 有一个渗透到语言中的借用检查器,这是它的定义特征。在 Rust 中,这样的代码是被禁止的。

C++ 是一门历史悠久的语言,我认为没有错误诊断的原因是因为在创建该语言时它不是问题。在那个时候,C 哲学是主流:“程序员无所不知”。因此,程序员知道他们违反了生命周期安全,因此错误消息是多余的。

现在,C++ 委员会全神贯注于确保 C++ 的版本尽可能向后兼容,并且强制提供的代码段失败可能会破坏现有代码。因此,不会在不久的将来将终生违规行为纳入标准。

对于此类问题,委员会似乎倾向于认为,如果您想强制执行标准未涵盖的内容,则应使用第三方静态分析工具。但是,其中很少,最值得注意的是clang-tidy,但据我所知,它们都不支持严格的生命周期分析来检测您的代码段所展示的错误。


推荐阅读