【问题标题】:Using std::vector<> and std::shared_ptr<> should cause error使用 std::vector<> 和 std::shared_ptr<> 应该会导致错误
【发布时间】:2015-06-08 22:50:32
【问题描述】:

这是我正在做的事情的代码:

#include <iostream>
#include <vector>
#include <memory>
using namespace std;

int main()
{
  vector<int> ar = {1};

  shared_ptr<int> sp(&ar[0]);

  cout<<*sp<<endl; // ---- [1]

  ar[0] = 10;

  cout<<*sp<<endl; // ---- [2]

  ar.clear();

  cout<<*sp<<endl; // ---- [3]



  return 0;
}

输出将是:

1
10
10

而不是cout [3] 我认为,运行时应该有任何错误,因为要访问的对象已经被删除。它是如何在[3] 中打印10 的?或者我应该使用任何g++ 标志,我只是使用g++ -std=c++14 a1.cpp &amp;&amp; ./a.out

编辑:在Coliru 上运行时,我发现clang++ 正在给予

`*** glibc detected *** ./a.out: double free or corruption (fasttop):     0x0000000002138010 ***`

但是g++ 不是Coliru

【问题讨论】:

  • 到达main末尾时不会崩溃吗?
  • @DavidRodriguez-dribeas 甚至没有崩溃,就像什么都没发生一样退出!
  • 清除向量并不一定意味着它分配的内存正在被删除。
  • 这是未定义的行为,未定义的行为是未定义的。它可能会崩溃,也可能不会。你所做的只是访问你不应该访问的内存,它不应该这样做,但它不一定是致命的。
  • 人们从哪里得到这样的想法,即编写糟糕的 C++ 代码意味着你肯定会崩溃?

标签: c++ c++11 g++ c++14


【解决方案1】:

当您尝试访问向量的当前边界之外时,您几乎绕过了任何会保证运行时错误的东西。

如果你想检查边界,你可以考虑这样的事情:

std::vector<int> ar { 1 };

std::cout << ar.at(0); // no problem

ar.clear();

std::cout << ar.at(0); // guaranteed to throw an exception

shared_ptr 用于共享 对象的所有权,因此只有在没有任何东西可以拥有它时才会删除该对象。相比之下,std::vector 假定它包含的所有对象唯一所有权,因此尝试使用 shared_ptr 引用其中一个对象只会导致问题。

另一方面,使用 gcc 可以在没有(可见)问题迹象的情况下退出这一事实在技术上并不符合编译器中的错误。在作用域结束时,shared_ptrstd::vector 都将尝试释放shared_ptr 所指的int——但不要求这样做会导致错误消息(官方称这是实施质量问题,尽管我当然同意显示信息总比不显示好)。

【讨论】:

    【解决方案2】:

    您的代码中有几处错误。最明显的一个是您正在创建一个shared_ptr 来管理一个已经由vector 管理的对象,并且很可能会在main 的末尾获得双重删除。

    另一个问题是你有一个指向对象的指针,并在对象被删除后使用它,因为std::vector&lt;int&gt;::clear 不会释放你正在访问的内存,而该内存仍然由向量,这就是它不会爆炸的原因,但对象不再存在,您不应该访问它。如果不是int,而是std::string,则程序可能已经崩溃(它也可能没有崩溃,这是未定义行为的本质)

    【讨论】:

    • 是的,我的程序 crashedstd::string。 :)
    【解决方案3】:

    这是一种未定义的行为。它可能会或可能不会打印 10。

    std::vector::clear() 删除了对象并且不保证重新分配。因此系统可能不会重用该内存,因此如果您访问相同的内存位置,您可能会得到旧值。

    有一个有趣的观察,如果你在std::vector::clear() 操作之后检查std::shared_ptr::use_cout(),你可以看到答案1。

      vector<int> ar = {1};
    
      shared_ptr<int> sp(&ar[0]);
    
      cout<<*sp<<"\n"; // ---- [1]
    
      ar[0] = 10;
    
      cout<<*sp<<"\n"; // ---- [2]
    
      ar.clear();
      cout<< sp.use_count()<<"\n";
    
      cout<<*sp<<endl; // ---- [3]
    

    输出

    1
    10
    1
    10
    

    【讨论】:

    • std::vector&lt;&gt;::clear() 不会释放,它仍然是由向量管理的内存。尽管如此,它仍然是未定义的行为,因为对象不再存在了。
    猜你喜欢
    • 2019-10-20
    • 1970-01-01
    • 2018-02-02
    • 1970-01-01
    • 1970-01-01
    • 2018-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多