Почему этот висячий std::weak_ptr не вызывает SEGFAULT?
В следующем коде я создаю shared_ptr
в объеме и назначить его weak_ptr
, Почему при запуске кода я не получаю SEGFAULT, потому что wp
должен быть недействительным вне области, верно?
namespace {
struct Dummy {
int x;
void foo() {
std::cout << "dummy created\n";
}
~Dummy()
{
std::cout << "dummy destroyed\n";
}
};
}
TEST(experimental, ptr_test){
std::weak_ptr<Dummy> wp;
{
auto sp = std::make_shared<Dummy>();
wp = sp;
}
wp.lock()->foo();
};
2 ответа
Вы на самом деле ничего не разыменовываете там. Метод блокировки по-прежнему будет возвращать shared_ptr, если заблокированный shared_ptr равен нулю, но этот shared_ptr также будет нулевым. В этом примере foo не падает на моем компиляторе, так как он никогда не разыменовывает нулевой указатель, но это неопределенное поведение, поэтому вы никогда не знаете, что произойдет. Тем не менее, бар всегда будет аварийно завершать работу, так как ему нужно разыменовать указатель, чтобы добраться до x.
Причина, по которой это работает, заключается в том, что все функции-члены компилируются в обычные функции, которые принимают указатель на объект в качестве своего первого параметра, доступного из тела функции, как этот. Вызов этой функции для nullptr, вероятно, будет работать большую часть времени, если ничто в теле функции не разыменовывает это. Вы не должны этого делать, хотя будущие изменения компилятора или порт на другую архитектуру могут привести к сбою.
#include <iostream>
#include <memory>
struct Dummy {
int x;
Dummy()
: x(10) {
std::cout << "Dummy created" << std::endl;
}
~Dummy() {
std::cout << "Dummy destroyed" << std::endl;
}
void foo() {
std::cout << "foo" << std::endl;
}
void bar() {
std::cout << x << std::endl;
}
};
int main() {
std::weak_ptr<Dummy> wp;
{
auto sp = std::make_shared<Dummy>();
wp = sp;
}
auto locked = wp.lock();
if(locked.get() == nullptr) {
std::cout << "Locked pointer is null" << std::endl;
}
locked->foo(); // Does not crash
((Dummy*)nullptr)->foo(); // Does not crash
locked->bar(); // Will crash
}
Как правило, вы не получите segfault, если не сделаете что-то с недопустимой памятью (и тогда это не всегда будет segfault - это зависит от оборудования, чтобы послать сигнал в ОС, а затем до ОС, чтобы фактически сбой программы). Если бы вы должны были установить x
в foo
У вас может быть больше шансов увидеть segfault - но, как указал user2357112, стандарт C++ не гарантирует segfault для некорректного кода.