使用 std::vector<> 和 std::shared_ptr<> 应该会导致错误
Using std::vector<> and std::shared_ptr<> should cause error
这是我正在做的代码:
#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 && ./a.out
编辑:在 Coliru 上的 运行 我发现 clang++
给出了
`*** glibc detected *** ./a.out: double free or corruption (fasttop): 0x0000000002138010 ***`
但是 g++
不是 Coliru。
这是一个未定义的行为。它可能打印也可能不打印 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
您的代码中有几处错误。最明显的一个是您正在创建一个 shared_ptr
来管理一个已经由 vector
管理的对象,并且很可能会在 main
结束时获得双重删除。
另一个问题是你有一个指向对象的指针并在对象被删除后使用它,因为std::vector<int>::clear
不会释放你正在使用的内存命中仍然由向量管理的内存,这就是它不会爆炸的原因,但是该对象不再存在,您不应该访问它。如果不是 int
而是 std::string
程序可能已经崩溃(它也可能没有崩溃,这是未定义行为的本质)
当您尝试访问向量的当前边界之外时,您几乎绕过了任何会保证 运行 时间错误的东西。
如果你想检查边界,你可以考虑这样的事情:
std::vector<int> ar { 1 };
std::cout << ar.at(0); // no problem
ar.clear();
std::cout << ar.at(0); // guaranteed to throw an exception
A shared_ptr
是对象的 shared 所有权,因此只有在没有任何东西可以拥有它时才会删除该对象。相比之下,std::vector
假定它包含的所有对象的 唯一 所有权,因此尝试使用 shared_ptr
引用其中一个对象只会导致问题。
另一方面,事实上,使用 gcc 这设法在没有(可见的)问题迹象的情况下退出,这在技术上不属于编译器中的错误。在作用域的末尾,shared_ptr
和 std::vector
都将尝试释放 shared_ptr
所指向的 int
——但不要求这样做会导致到错误消息(正式来说这是实施质量问题,但我当然同意显示消息总比不显示好)。
这是我正在做的代码:
#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 && ./a.out
编辑:在 Coliru 上的 运行 我发现 clang++
给出了
`*** glibc detected *** ./a.out: double free or corruption (fasttop): 0x0000000002138010 ***`
但是 g++
不是 Coliru。
这是一个未定义的行为。它可能打印也可能不打印 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
您的代码中有几处错误。最明显的一个是您正在创建一个 shared_ptr
来管理一个已经由 vector
管理的对象,并且很可能会在 main
结束时获得双重删除。
另一个问题是你有一个指向对象的指针并在对象被删除后使用它,因为std::vector<int>::clear
不会释放你正在使用的内存命中仍然由向量管理的内存,这就是它不会爆炸的原因,但是该对象不再存在,您不应该访问它。如果不是 int
而是 std::string
程序可能已经崩溃(它也可能没有崩溃,这是未定义行为的本质)
当您尝试访问向量的当前边界之外时,您几乎绕过了任何会保证 运行 时间错误的东西。
如果你想检查边界,你可以考虑这样的事情:
std::vector<int> ar { 1 };
std::cout << ar.at(0); // no problem
ar.clear();
std::cout << ar.at(0); // guaranteed to throw an exception
A shared_ptr
是对象的 shared 所有权,因此只有在没有任何东西可以拥有它时才会删除该对象。相比之下,std::vector
假定它包含的所有对象的 唯一 所有权,因此尝试使用 shared_ptr
引用其中一个对象只会导致问题。
另一方面,事实上,使用 gcc 这设法在没有(可见的)问题迹象的情况下退出,这在技术上不属于编译器中的错误。在作用域的末尾,shared_ptr
和 std::vector
都将尝试释放 shared_ptr
所指向的 int
——但不要求这样做会导致到错误消息(正式来说这是实施质量问题,但我当然同意显示消息总比不显示好)。