z63*_*318 1 c++ unique-ptr c++14
C++的新手,并试图了解对象的生命周期和智能指针.
为什么以这种方式使用get()从unique_ptr创建原始指针的结果:
auto w = (std::make_unique<Wall>()).get();
Run Code Online (Sandbox Code Playgroud)
导致一个指针传递一个空检查,但在使用时导致无效读取(并且根据valgrind看起来像是由Wall析构函数中的双重删除引起的?)但是当以两步方式创建时:
auto wall = std::make_unique<Wall>();
auto w = wall.get();
Run Code Online (Sandbox Code Playgroud)
目前没有这样的问题?
所以我有两个问题:
(1)为什么第一种方式导致原始指针导致无效读取而第二种方式不导致?
(2)为什么无效的读指针通过空检查?
#include <iostream>
#include <memory>
#include <string>
class Object {
public:
virtual ~Object() = 0;
virtual void talk() {}
};
Object::~Object() {}
class Wall: public Object {
public:
virtual ~Wall() {}
virtual void talk() { std::cout << "I'm a wall." << std::endl; }
};
int main(int argc, char** argv) {
//auto wall = std::make_unique<Wall>();
//auto w = str.get();
auto w = (std::make_unique<Wall>()).get();
if (!w)
std::cout << "null pointer..." << std::endl;
w->talk();
}
Run Code Online (Sandbox Code Playgroud)
valgrind输出:
==21668== Memcheck, a memory error detector
==21668== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==21668== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==21668== Command: ./wall
==21668==
==21668== Invalid read of size 8
==21668== at 0x402452: main (main.cpp:33)
==21668== Address 0x5ab6c80 is 0 bytes inside a block of size 8 free'd
==21668== at 0x4C2F24B: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21668== by 0x402548: Wall::~Wall() (main.cpp:15)
==21668== by 0x402955: std::default_delete<Wall>::operator()(Wall*) const (unique_ptr.h:76)
==21668== by 0x40269C: std::unique_ptr<Wall, std::default_delete<Wall> >::~unique_ptr() (unique_ptr.h:236)
==21668== by 0x40242A: main (main.cpp:27)
==21668== Block was alloc'd at
==21668== at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21668== by 0x4025CD: _ZSt11make_uniqueI4WallIEENSt9_MakeUniqIT_E15__single_objectEDpOT0_ (unique_ptr.h:765)
==21668== by 0x40240E: main (main.cpp:27)
Run Code Online (Sandbox Code Playgroud)
在
auto w = (std::make_unique<Wall>()).get();
Run Code Online (Sandbox Code Playgroud)
匿名std::make_unique<Wall>()只存在直到行尾.然后它超出范围并被销毁,带有包含它的指针.
这会在w不知情的情况下将指针从下方删除w.w传递null检查,因为它不是null,但不能使用它指向的位置.
在你的第二个例子中
auto wall = std::make_unique<Wall>();
auto w = wall.get();
Run Code Online (Sandbox Code Playgroud)
wall保持unique_ptr直到wall超出范围,希望足够长,以利用w.
我的建议是全程丢弃w和使用wall.这样就没有机会悬挂指针.
#include <iostream>
#include <memory>
#include <string>
class Object {
public:
virtual ~Object() = 0;
virtual void talk() {}
};
Object::~Object() {}
class Wall: public Object {
public:
virtual ~Wall() {}
virtual void talk() { std::cout << "I'm a wall." << std::endl; }
};
int main(int argc, char** argv) {
auto wall = std::make_unique<Wall>();
if (!wall)
std::cout << "null pointer..." << std::endl;
wall->talk();
wall.reset();
if (!wall)
std::cout << "null pointer..." << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
预期产量:
I'm a wall.
null pointer...
Run Code Online (Sandbox Code Playgroud)