c++中智能指针中的“智能”可以简单的理解为自动释放内存,这样就可以避免内存泄漏。具体怎么避免内存?它是怎样释放内存的呢?
智能指针的实现是使用了RAII机制,即:资源获取即初始化。也就是说在对象构造的时候申请内存(资源),在对象生存周期结束的时候,在析构函数中释放内存。
智能指针也是一个对象,是对c语言原生指针的封装,当智能指针的生存周期结束时,他会在析构函数中自动把他指向的对象给销毁。
shared_ptr和unique_ptr的区别是它允许多个shared_ptr共享同一个对象。它的实现内部有一个引用计算用来记录,一共有多少个shared_ptr共享对象。这个对象什么时候销毁呢?直到没有shared_ptr占有这个对象,即引用计数为0的时候自动销毁对象。
也就是说一旦最后一个这样的shared_ptr被销毁,也就是一旦某个对象的引用计数变为0,这个对象会被自动销毁。
make_shared
一般使用make_shared来创建一个智能指针。
#include <iostream>
#include <memory>
struct C
{
C(int i) : i(i) {}
int i;
};
int main()
{
auto sp = std::make_shared<C>(12);
std::cout << sp->i << '\n';
}
输出:
12
下面介绍一些常用的成员函数
get
返回共享对象的地址,返回值是一个指针。
#include <iostream>
#include <memory>
#include <string_view>
void output(std::string_view msg, int const* pInt)
{
std::cout << msg << *pInt << " in " << pInt << "\n";
}
int main()
{
int* pInt = new int(42);
std::shared_ptr<int> pShared = std::make_shared<int>(42);
output("Naked pointer ", pInt);
// output("Shared pointer ", pShared); // compiler error
output("Shared pointer with get() ", pShared.get());
delete pInt;
}
输出:
Naked pointer 42 in 0x0000546 Shared pointer with get() 42 in 0x0000154
reset
取消shared_ptr 对象与相关指针的关联,它将引用计数减少1,如果引用计数变为0,则删除对象。
#include <memory>
#include <iostream>
struct Foo {
Foo(int n = 0) noexcept : bar(n) {
std::cout << "Foo: constructor, bar = " << bar << '\n';
}
~Foo() {
std::cout << "Foo: destructor, bar = " << bar << '\n';
}
int getBar() const noexcept { return bar; }
private:
int bar;
};
int main()
{
std::shared_ptr<Foo> sptr = std::make_shared<Foo>(1);
std::cout << "The first Foo's bar is " << sptr->getBar() << "\n";
// 重置shared_ptr, 把它指向一个新的Foo对象
// reset之后旧的Foo对象将会被销毁
sptr.reset(new Foo);
std::cout << "The second Foo's bar is " << sptr->getBar() << "\n";
}
输出:
Foo: constructor, bar = 1 The first Foo's bar is 1 Foo: constructor, bar = 0 Foo: destructor, bar = 1 The second Foo's bar is 0 Foo: destructor, bar = 0
接下来看一段演示代码,代码很简单,创建一个指向derived对象的shared_ptr,然后把它作为参数开启三个线程执行thr函数。
#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <mutex>
struct Base
{
Base() { std::cout << " Base::Base()\n"; }
// Note: non-virtual destructor is OK here
~Base() { std::cout << " Base::~Base()\n"; }
};
struct Derived: public Base
{
Derived() { std::cout << " Derived::Derived()\n"; }
~Derived() { std::cout << " Derived::~Derived()\n"; }
};
void thr(std::shared_ptr<Base> p)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::shared_ptr<Base> lp = p; // thread-safe, even though the
// shared use_count is incremented
{
static std::mutex io_mutex;
std::lock_guard<std::mutex> lk(io_mutex);
std::cout << "local pointer in a thread:\n"
<< " lp.get() = " << lp.get()
<< ", lp.use_count() = " << lp.use_count() << '\n';
}
}
int main()
{
std::shared_ptr<Base> p = std::make_shared<Derived>();
std::cout << "Created a shared Derived (as a pointer to Base)\n"
<< " p.get() = " << p.get()
<< ", p.use_count() = " << p.use_count() << '\n';
std::thread t1(thr, p), t2(thr, p), t3(thr, p);
p.reset(); // release ownership from main
std::cout << "Shared ownership between 3 threads and released\n"
<< "ownership from main:\n"
<< " p.get() = " << p.get()
<< ", p.use_count() = " << p.use_count() << '\n';
t1.join(); t2.join(); t3.join();
std::cout << "All threads completed, the last one deleted Derived\n";
}
他的输出如下:
Base::Base() Derived::Derived() Created a shared Derived (as a pointer to Base) p.get() = 0x2299b30, p.use_count() = 1 Shared ownership between 3 threads and released ownership from main: p.get() = 0, p.use_count() = 0 local pointer in a thread: lp.get() = 0x2299b30, lp.use_count() = 5 local pointer in a thread: lp.get() = 0x2299b30, lp.use_count() = 3 local pointer in a thread: lp.get() = 0x2299b30, lp.use_count() = 2 Derived::~Derived() Base::~Base() All threads completed, the last one deleted Derived
本文详细介绍了C++中智能指针的概念,如何通过RAII机制避免内存泄漏,以及shared_ptr和unique_ptr的区别。通过示例代码展示了智能指针的get、reset成员函数的使用,并解释了多线程环境下智能指针的安全性。
2356

被折叠的 条评论
为什么被折叠?



