【问题标题】:Creating pointers inside a for loop results in pointing to same memory address在 for 循环中创建指针会导致指向相同的内存地址
【发布时间】:2020-02-17 01:30:53
【问题描述】:

我有一个对象,我试图复制任意多次,并对该对象进行了一些细微的更改。我想将指向那些重复对象的指针存储在std::vector 中。我正在使用for 循环来尝试实现结果。但是,我注意到std::vector<T *> 在循环退出后指向相同的地址。我尝试用std::string 复制对象,我看到了相同的效果。这是我的代码 sn-p。

int main() {
  auto name = new std::string("fido");

  const int size = 3;
  std::vector<std::string *> names;
  names.reserve(size);

  for (int i = 0; i < size; i++) {
    std::string n = *name + " " + std::to_string(i);
    names.push_back(&n);
  }

  // nothing from this loop prints out
  for (auto n : names) {
    std::cout << *n << std::endl;
  }

  return 0;
}

当我将代码放入调试器时,我看到names 将指针全部存储到相同的内存地址:0x7ffffffeead0。关于我在这里做错了什么有什么想法吗?

我修改了代码来存储一个字符串向量,然后循环遍历每个字符串,创建一个指向每个字符串地址的指针,如下所示。这种方法也行不通。指针向量仍然指向同一个地址;虽然这一次,它们都指向最后一个字符串的地址。

int main() {
  auto name = new std::string("fido");

  const int size = 3;
  std::vector<std::string *> pointers;
  std::vector<std::string> names;

  names.reserve(size);
  pointers.reserve(size);

  for (int i = 0; i < size; i++) {
    std::string n = *name + " " + std::to_string(i);
    names.push_back(n);
  }

  for (int i = 0; i < size; i++) {
    auto n = names.at(i);
    auto p = &n;
    pointers.push_back(p);
  }

  for (auto n : names) {
    std::cout << n << std::endl;
  }

  for (auto n : pointers) {
    std::cout << *n << std::endl;
  }

  return 0;
}

然而,在第三次尝试中,我将代码修改如下。请注意,我使用&amp; 运算符来按索引访问元素。在这里,我确实得到了一个指向不同地址的std::vector&lt;std::string *&gt;(正确对应于字符串向量)。

int main() {
  auto name = new std::string("fido");

  const int size = 3;
  std::vector<std::string *> pointers;
  std::vector<std::string> names;

  names.reserve(size);
  pointers.reserve(size);

  for (int i = 0; i < size; i++) {
    std::string n = *name + " " + std::to_string(i);
    names.push_back(n);
  }

  for (int i = 0; i < size; i++) {
    auto p = &names.at(i); // using address operator like this "works"
    pointers.push_back(p);
  }

  for (auto n : names) {
    std::cout << n << std::endl;
  }

  for (auto n : pointers) {
    std::cout << *n << std::endl;
  }

  return 0;
}

最后,我终于得到了这个更简洁的例子。在这里,我在每个循环上创建一个新指针。

int main() {
  auto name = new std::string("fido");

  const int size = 3;
  std::vector<std::string *> names;
  names.reserve(size);

  for (int i = 0; i < size; i++) {
    auto x = new std::string(*name + " " + std::to_string(i));
    names.push_back(x);
  }

  for (auto n : names) {
    std::cout << *n << std::endl;
  }

  return 0;
}

for-loops 上是否有一些我在这里遗漏的指针?任何指向 C++ 范围规则的指针(不是双关语)都将不胜感激。

【问题讨论】:

    标签: c++ for-loop pointers c++17


    【解决方案1】:

    但是,我注意到 std::vector 在循环退出后指向相同的地址。

    关于我在这里做错了什么有什么想法吗?

    for (int i = 0; i < size; i++) {
        std::string n = *name + " " + std::to_string(i);
    

    这里,n 是一个自动变量。 n - 像所有具有自动存储的对象一样,将在作用域结束时销毁,即在迭代结束时。

        names.push_back(&n);
    

    在这里,您获取自动对象的地址并将其存储在向量中。

    }
    

    到此,迭代结束,下一个开始。 n 已被破坏,向量中的指针无效。在下一次迭代中,将创建一个新的 n 对象。由于之前的n被销毁了,同样的内存可以用于下一个对象。

    for (auto n : pointers) {
        std::cout << *n << std::endl;
    

    在这一行中,您尝试通过无效指针访问不存在的字符串,并且程序的行为未定义。

    相同的模式在您的第二次和第三次尝试中持续存在。

    在包括第四个在内的所有示例中,您都会泄漏内存。


    我有一个对象,我试图复制任意次数

    您可以将字符串存储在std::vector&lt;std::string&gt; 中。你可以像这样复制这样的向量:

    std::vector<std::string> names;
    // insert names here
    
    std::vector<std::string> duplicates = names;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-07
      • 2016-02-08
      • 1970-01-01
      • 1970-01-01
      • 2016-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多