我有使用的成员函数(方法)
std::enable_shared_from_this::weak_from_this()
Run Code Online (Sandbox Code Playgroud)
简而言之:weak_from_this返回weak_ptr到这个。一个警告是它不能从构造函数中使用。如果有人使用继承的类的构造函数中的函数,则该函数weak_from_this将返回expired weak_ptr。我通过断言检查它是否未到期来进行防范,但这是运行时检查。
有没有一种方法可以在编译时进行检查?
有没有办法将std :: bind绑定到std :: weak_ptr?我想存储一个"弱函数"回调,当被调用者被销毁时,它会自动"断开连接".
我知道如何使用shared_ptr创建一个std :: function:
std::function<void()> MyClass::GetCallback()
{
return std::function<void()>(std::bind(&MyClass::CallbackFunc, shared_from_this()));
}
Run Code Online (Sandbox Code Playgroud)
但是返回的std :: function使我的对象永远保持活着.所以我想将它绑定到weak_ptr:
std::function<void()> MyClass::GetCallback()
{
std::weak_ptr<MyClass> thisWeakPtr(shared_from_this());
return std::function<void()>(std::bind(&MyClass::CallbackFunc, thisWeakPtr));
}
Run Code Online (Sandbox Code Playgroud)
但那不编译.(std :: bind将不接受weak_ptr!)有没有办法绑定到weak_ptr?
我已经找到了关于这个的讨论(见下文),但似乎没有标准的实现.存储"弱功能"的最佳解决方案是什么,特别是如果Boost不可用?
讨论/研究(所有这些都使用Boost并且没有标准化):
与使用原始指针的类似(但不限于)某些高级技术相比,每个智能指针的等效用途是什么?
我的理解很少,但我可以收集到:
std::shared_ptr::reset底层时deallocator.std::shared_ptr不增加引用计数的子类型,当其父级std::shared_ptr不再存在时无效.可能会返回无效的引用.使用前请务必检查.RAW指针等效示例
引用计数,缓存实现: std::map<std::string, std::pair<long, BITMAP*> > _cache;
拥有所有权的单身人士:
class Keyboard {
public:
//...
static Keyboard* CreateKeyboard();
~Keyboard();
//...
private:
//...
Keyboard();
static Keyboard* _instance;
//...
};
Run Code Online (Sandbox Code Playgroud)
聚合容器,无所有权:空间分区图和树,迭代容器等.
复合容器,所有权:大型对象.
- 编辑 -
在我工作的时候,我遇到了一个有趣的案例,DeadMG指出智能指针应该被用作简单的抽象来处理资源管理; 那些在声明点无法在堆上创建但必须在以后创建的文件范围对象呢?
a的控制块shared_ptr保持活动,同时存在至少一个weak_ptr存在.如果创建共享指针make_shared,则意味着保持分配对象的整个内存.(对象本身被正确销毁,但由于控件块和对象的内存分配在一个块make_shared中,因此它们只能一起解除分配.)
我的理解是否正确?
看起来这种行为代表了一个问题,例如在着名的"缓存示例"中.对象的内存将永远分配.
这在任何实际情况下都是一个问题吗?应该shared_ptr在这种情况下使用构造函数创建(大对象和意图使用weak_ptrs)?
class MyClass {
public:
MyClass(std::weak_ptr<MyClass> parent){}
}
Run Code Online (Sandbox Code Playgroud)
我想做这个:
auto newInstance = std::make_shared<MyClass>(nullptr);
Run Code Online (Sandbox Code Playgroud)
或者weak_ptr参数的默认值为null,例如:
void function(int arg,std::weak_ptr<MyClass> obj = nullptr);
Run Code Online (Sandbox Code Playgroud)
但是,我需要的是这样做:
auto newInstance = std::make_shared<MyClass>(std::shared_ptr<MyClass>(nullptr));
Run Code Online (Sandbox Code Playgroud)
这是为什么?
请考虑以下代码:
#include <iostream>
#include <memory>
using namespace std;
class T;
std::weak_ptr<T> wptr;
class T
{
public:
T() { }
~T() {
std::cout << "in dtor" << std::endl;
std::cout << (wptr.expired() ? "expired" : "not expired") << std::endl;
}
};
int main() {
{
auto ptr = std::make_shared<T>();
wptr = ptr;
std::cout << (wptr.expired() ? "expired" : "not expired") << std::endl;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在这段代码中,我试图找出weak_ptrs在对象销毁阶段是否过期.看来是这样.输出是:
not expired
in dtor
expired
Run Code Online (Sandbox Code Playgroud)
我用gcc-5.1和ideone.
现在,我有另一个问题.我找不到任何文档说明这是标准行为.难道是保证这样的工作方式,始终?
有没有办法区分分配的(可能已过期的)weak_ptr和未分配的weak_ptr.
weak_ptr<int> w1;
weak_ptr<int> w2 = ...;
Run Code Online (Sandbox Code Playgroud)
我理解以下检查未分配或到期,但有没有(更便宜?)检查只有非转让?
if (!w.lock()) { /* either not assigned or expired */ }
Run Code Online (Sandbox Code Playgroud) std::shared_ptr<int> g_s = std::make_shared<int>(1);
void f1()
{
std::shared_ptr<int>l_s1 = g_s; // read g_s
}
void f2()
{
std::shared_ptr<int> l_s2 = std::make_shared<int>(3);
std::thread th(f1);
th.detach();
g_s = l_s2; // write g_s
}
Run Code Online (Sandbox Code Playgroud)
关于上面的代码,我知道不同的线程读取和写入相同的shared_ptr导致竞争条件.但是怎么样weak_ptr?下面的代码中是否有竞争条件?(我的平台是Microsoft VS2013.)
std::weak_ptr<int> g_w;
void f3()
{
std::shared_ptr<int>l_s3 = g_w.lock(); //2. here will read g_w
if (l_s3)
{
;/.....
}
}
void f4()
{
std::shared_ptr<int> p_s = std::make_shared<int>(1);
g_w = p_s;
std::thread th(f3);
th.detach();
// 1. p_s destory will motify g_w (write g_w)
}
Run Code Online (Sandbox Code Playgroud) 例如:
std::weak_ptr<int> wp1(std::make_shared<int>());
std::weak_ptr<int> wp2;
assert(PointsToValidOrExpiredObject(wp1));
assert(!PointsToValidOrExpiredObject(wp2));
Run Code Online (Sandbox Code Playgroud)
这样的功能可能吗?
用例:类的构造函数std::weak_ptr<Foo>作为依赖项.传递过期的对象是可以的(可能在某些工作流程中发生),但传递null意味着程序员忘记了某些事情.我想测试它作为构造函数的参数验证的一部分.
c++ ×10
weak-ptr ×10
c++11 ×6
shared-ptr ×6
auto-ptr ×1
bind ×1
c++14 ×1
c++17 ×1
callback ×1
casting ×1
constructor ×1
make-shared ×1
null ×1
std-function ×1
unique-ptr ×1