我正在玩c ++ - 想法,并且对这个问题有点困惑.
我想要一个LIFO管理资源池的类.当请求资源(通过acquire())时,它返回对象作为unique_ptr删除后的对象,导致资源返回到池中.
单元测试将是:
// Create the pool, that holds (for simplicity, int objects)
SharedPool<int> pool;
TS_ASSERT(pool.empty());
// Add an object to the pool, which is now, no longer empty
pool.add(std::unique_ptr<int>(new int(42)));
TS_ASSERT(!pool.empty());
// Pop this object within its own scope, causing the pool to be empty
{
auto v = pool.acquire();
TS_ASSERT_EQUALS(*v, 42);
TS_ASSERT(pool.empty());
}
// Object should now have returned to the pool
TS_ASSERT(!pool.empty())
Run Code Online (Sandbox Code Playgroud)
基本实现,除了重要的最终测试外,将通过测试:
template <class T>
class SharedPool …Run Code Online (Sandbox Code Playgroud) 我已经看到一些std::shared_ptr与自定义删除器一起使用的代码,该自定义删除器测试nullptr的参数,例如,MyClass它有一个close()方法并且由一些构造CreateMyClass:
auto pMyClass = std::shared_ptr<MyClass>(CreateMyClass(),
[](MyClass* ptr)
{
if(ptr)
ptr->close();
});
Run Code Online (Sandbox Code Playgroud)
ptr在删除器中测试null-ness 是否有意义?这会发生吗?怎么样?
假设我有一些任意的类,A:
class A {
//... stuff
};
Run Code Online (Sandbox Code Playgroud)
我想调用一个外部API,它接受一个类型的共享指针,就像这样(我不能改变这个接口):
//...much later
void foo(std::shared_ptr<A> _a){
//operate on _a as a shared_ptr
}
Run Code Online (Sandbox Code Playgroud)
但是,在我正在使用的(遗留)代码中,我正在使用的类A实例被分配在堆栈上(我无法解决):
A a;
//...some stuff on a
//Now time to call foo
Run Code Online (Sandbox Code Playgroud)
除此之外,A类的实例非常大,每个实例大约1 GB.
我知道我可以打电话
foo(std::make_shared<A> a);
Run Code Online (Sandbox Code Playgroud)
但这会为A副本分配内存,我真的很想避免.
有没有办法将一些调用std::make_shared(可能是move语义)一起破解,这样我就不会被迫为另一个A类实例分配内存?
我尝试过这样的事情:
foo(std::make_shared<A>(std::move(a)));
Run Code Online (Sandbox Code Playgroud)
但据我所知,A仍然创造了一个新的实例.
#include <iostream>
#include <memory>
using namespace std;
class A{
public:
A(int _var=42) : var(_var){cout << "Default" << endl;}
A(const A& _rhs) : var(_rhs.var){cout << …Run Code Online (Sandbox Code Playgroud) 例如,有一个函数可以找到一个对象,如果找到了对象则返回shared_ptr,并且必须以某种方式指示没有找到对象.
std::vector<std::shared_ptr> Storage::objects;
std::shared_ptr<Object> Storage::findObject()
{
if (objects.find)
{
return objects[x];
}
else
{
return nullptr;
}
}
std::shared_ptr<Object> obj = Storage::findObject();
if (obj)
{
print("found");
}
else
{
print("not found");
}
Run Code Online (Sandbox Code Playgroud)
返回使用nullptr隐式初始化的shared_ptr是否正确?它会起作用,但可以这样做吗?或者我应该返回shared_ptr默认构造而不是?
怎么会是weak_ptr?检查空weak_ptr已被返回的正确方法是什么?by weak_ptr :: expired函数还是有其他方法吗?如果通过weak_ptr :: expired检查是唯一的方法那么我如何区分该函数返回空指针,或者对象刚被删除(多线程环境)?
首先,我确实意识到这与shared_ptr的目的完全矛盾.我正在处理一些库代码,其中ParticleSystem的实例期望在构造期间将shared_ptr传递给它们以设置用于每个粒子的纹理.问题是,我已经以我的纹理具有混凝土所有权的方式构建了我的程序的其余部分(如果这是正确的术语) - TextureCache拥有所有纹理.所以我需要一种方法来处理这个ParticleSystem类,而不允许它删除我的纹理.如果我只是简单地创建一个新实例,ParticleSystem(std::shared_ptr<Texture>&myTexture)那么它会在破坏时尝试破坏纹理(这是一个不需要的和无效的操作,因为我的纹理甚至没有创建new).
我看到这个问题的最简洁的方法是这样的:
我相信这个解决方案是合理的,但它仍然感觉非常黑客.有没有更好的方法来解决我的问题?
C++ std::shared_ptr<..>可能为空,也可能为null.这两个概念都存在,并且它们不相同.此外,这两种情况之间并不总是如此.
后一种情况很容易检测,因为operator bool提供了精确的测试.根据文档,它"检查是否*this存储非空指针,即是否get() != nullptr."
是否对前一种情况进行了测试,事情是空的?
我对此的使用非常简单.我有一个具有静态工厂方法的类.静态工厂方法内部是shared_ptr类的实例的静态本地,初始化为nullptr.对该工厂方法的第一次调用构造了一个类的实例,并shared_ptr在返回它的副本之前初始化静态local - 这是由a守护的mutex.这shared_ptr可以由任何东西保存,复制和传递,可以通过对静态工厂的额外调用来获取更多副本,并且最后,当所有副本被破坏时,shared_ptr删除器会破坏实例.
实例本身是使用遗留的C API创建和破坏的,由我的类包装,虽然这些实例旨在作为单例共享,但它们也需要在不再需要时进行清理 - 与单例不同.
目前,我正在使用空检查来决定是shared_ptr应该初始化静态本地还是仅复制静态本地.我担心这个测试无法检测需要重新初始化的情况 - 例如,如果某些事情在所有先前用户放弃其引用并且共享实例被删除之后的某个时间尝试获取实例.
或者shared_ptr,nullptr如果引用计数降为零并且调用了删除器,则重置为是吗?也适用于自定义删除者?
许多程序员提倡使用make_shared它,因为它减少了键入并减少了编程错误.然而,在某些情况下使用构造函数shared_ptr是不可避免的.其中一种情况是你有一个你想要拥有的现有指针shared_ptr,因为它shared_ptr<Foo>(&existing_ptr)是错误的代码.相反,你必须使用笨重的shared_ptr<Foo>(shared_ptr<Foo>(), p).你不仅要重复自己,还要创建一个临时对象.
int main()
{
using namespace std;
Foo foo;
foo.n = 1;
{
auto ptr = make_shared<Foo>(move(foo));
ptr->n = 42;
cout << ptr->n << " " << foo.n << '\n';
}
{
auto p = &foo;
auto ptr = shared_ptr<Foo>(shared_ptr<Foo>(), p);
ptr->n = 42;
cout << ptr->n << " " << foo.n << '\n';
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
Foo::Foo()
Foo::Foo(Foo &&)
42 1
Foo::~Foo()
42 42
Foo::~Foo()
Run Code Online (Sandbox Code Playgroud)
什么是有一个更简洁的方式shared_ptr …