我的接口函数返回一个指向对象的指针.用户应该拥有该对象的所有权.我不想返回Boost.shared_ptr,因为我不想强制客户端使用boost.但是,在内部,我想将指针存储在shared_ptr中,以防止在异常等情况下发生内存泄漏.似乎无法从共享指针中分离指针.这里有什么想法?
我想比较两个std :: weak_ptr或一个std :: weak_ptr和一个std :: shared_ptr的相等性.
我想知道的是weak_ptr/shared_ptr指向的每个对象是否相同.比较应该产生负面结果,不仅如果地址不匹配,而且如果基础对象被删除然后偶然使用相同地址重建.
所以基本上,即使分配器保留相同的地址,我也希望这个断言成立:
auto s1 = std::make_shared<int>(43);
std::weak_ptr<int> w1(s1);
s1.reset();
auto s2 = std::make_shared<int>(41);
std::weak_ptr<int> w2(s2);
assert(!equals(w1,w2));
Run Code Online (Sandbox Code Playgroud)
weak_ptr模板不提供相等的运算符,正如我所理解的那样,这是有充分理由的.
所以一个天真的实现看起来像这样:
template <typename T, typename U>
inline bool naive_equals(const std::weak_ptr<T>& t, const std::weak_ptr<U>& u)
{
return !t.expired() && t.lock() == u.lock();
}
template <typename T, typename U>
inline bool naive_equals(const std::weak_ptr<T>& t, const std::shared_ptr<U>& u)
{
return !t.expired() && t.lock() == u;
}
Run Code Online (Sandbox Code Playgroud)
如果第一个weak_ptr在此期间到期,则它会产生0.如果不是,我将weak_ptr升级为shared_ptr并比较地址.
这个问题是我必须锁定weak_ptr两次(一次)!我担心花费太多时间.
我想出了这个:
template <typename T, typename U>
inline bool equals(const …Run Code Online (Sandbox Code Playgroud) 我有一个定义如下的函数:
void foo(std::shared_ptr<X> x) { ... };
Run Code Online (Sandbox Code Playgroud)
如果我将共享ptr声明为X:
std::shared_ptr<X> sourcePtr(new X(...));
Run Code Online (Sandbox Code Playgroud)
然后我可以打电话foo如下:
foo(std::move(sourcePtr));
Run Code Online (Sandbox Code Playgroud)
要么
foo(sourcePtr);
Run Code Online (Sandbox Code Playgroud)
我明白,如果我使用第一个选项,则sourcePtr变为null.它是否也会阻止引用计数递增?
如果这无关紧要,我更喜欢哪个选项?做出这样的决定时,我应该考虑其他事情吗?
我有一个继承自的类型enable_shared_from_this<type>,以及从这种类型继承的另一种类型.现在我不能使用shared_from_this方法,因为它返回基类型,并且在特定的派生类方法中我需要派生类型.从这个直接构造shared_ptr是否有效?
编辑:在一个相关的问题中,我如何从一个类型的左值移动shared_ptr<base>到一个类型shared_ptr<derived>?我使用dynamic_cast来验证它确实是正确的类型,但现在我似乎无法完成实际的移动.
我reset()用作shared_pointer的默认值(相当于a NULL).
但是如何检查shared_pointer是否是NULL?
这会返回正确的价值吗?
boost::shared_ptr<Blah> blah;
blah.reset()
if (blah == NULL)
{
//Does this check if the object was reset() ?
}
Run Code Online (Sandbox Code Playgroud) boost::shared_ptr 有一个不寻常的构造函数
template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p);
Run Code Online (Sandbox Code Playgroud)
我对这对什么有用感到有些疑惑.基本上它与股份共享r,但.get()将返回p.不 r.get()!
这意味着您可以执行以下操作:
int main() {
boost::shared_ptr<int> x(new int);
boost::shared_ptr<int> y(x, new int);
std::cout << x.get() << std::endl;
std::cout << y.get() << std::endl;
std::cout << x.use_count() << std::endl;
std::cout << y.use_count() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
你会得到这个:
0x8c66008
0x8c66030
2
2
Run Code Online (Sandbox Code Playgroud)
请注意,指针是分开的,但它们都声称具有use_count2(因为它们共享同一对象的所有权).
因此,所int拥有的x将存在只要x 或 即将存在y.如果我理解文档是正确的,那么第二个int永远不会被破坏.我通过以下测试程序证实了这一点:
struct T {
T() { std::cout << …Run Code Online (Sandbox Code Playgroud) 我正在研究一段代码,它有许多可能的故障点,导致它提前退出函数.我正在与之交互的库要求将C样式的数组传递给函数.所以,我没有在每个出口点调用数组上的delete,而是这样做:
void SomeFunction(int arrayLength)
{
shared_ptr<char> raiiArray(new char[arrayLength]);
pArray = raiiArray.get();
if(SomeFunctionThatRequiresCArray(pArray) == FAILED) { return; }
//etc.
}
Run Code Online (Sandbox Code Playgroud)
我想使用unique_ptr,但我当前的编译器不支持它,并且引用计数开销在这种情况下并不重要.
我只是想知道在与遗留代码接口时是否有人对这种做法有任何想法.
更新 我完全忘了shared_ptr呼叫delete而不是delete [].我刚看到没有内存泄漏,并决定采用它.甚至没想过用矢量.因为我最近一直在钻研新的(对我来说)C++我认为我有一个案例"如果你拥有的唯一工具是锤子,那么一切看起来都像钉子一样." 综合征.感谢您的反馈.
UPDATE2我想我会改变这个问题并提供一个答案,让那些犯了同样错误的人更有价值.虽然有类似的替代方案scoped_array,shared_array并且vector,您可以使用a shared_ptr来管理数组的范围(但在此之后我不知道为什么我会想要):
template <typename T>
class ArrayDeleter
{
public:
void operator () (T* d) const
{
delete [] d;
}
};
void SomeFunction(int arrayLength)
{
shared_ptr<char> raiiArray(new char[arrayLength], ArrayDeleter<char>());
pArray = raiiArray.get();
if(SomeFunctionThatRequiresCArray(pArray) == FAILED) { return; }
//etc. …Run Code Online (Sandbox Code Playgroud) 如该代码所示这里,从make_shared返回的对象的大小是两个指针.
但是,为什么不能make_shared像下面这样工作(假设T是我们正在制作共享指针的类型):
结果
make_shared是一个指针大小,它指向已分配的大小内存sizeof(int) + sizeof(T),其中int是引用计数,并且这在指针的构造/销毁时递增和递减.
unique_ptrs只是一个指针的大小,所以我不确定为什么共享指针需要两个.据我所知,它需要一个引用计数,它make_shared可以与对象本身一起放置.
此外,是否有任何实现以我建议的方式实现(不必intrusive_ptr为特定对象使用s)?如果没有,我建议实施的原因是什么原因可以避免?
我是shared_ptr的新手,我正试图弄清楚.reset()函数的确切功能.
#include <memory>
#include <stdio>
using namespace std;
class SomeClass{};
int main()
{
shared_ptr<SomeClass> sp (nullptr);
//do some stuff, sp now has 10 co-owners
cout << sp.use_count << endl;
sp.reset();
cout << sp.use_count << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
会输出
10
0
Run Code Online (Sandbox Code Playgroud)
因为我使用了reset函数是从内存中删除了所有实例吗?因为,我刚刚用sp消除了任何可能的内存泄漏?显然,这是一个我快速编写的玩具示例,对不起,如果有任何错误.
跟进情况:
shared_ptr<SomeClass> returnThis() {
shared_ptr<SomeClass> someObject(new SomeClass(/*default constructor for example*/) );
return someObject;
}
Run Code Online (Sandbox Code Playgroud)
在主要的地方:
shared_ptr<SomeClass> mainObject;
mainObject = returnThis();
Run Code Online (Sandbox Code Playgroud)
mainObject的使用次数是否为2,因为someObject是在函数中创建但从未清除过的?或者它是一个,并在返回值时自动完成清理?
在boost的实现中shared_ptr,它使用宽松的内存排序来增加其引用计数.这似乎是安全的,因为减量使用获取/释放来确保在释放内存之前线程可以看到任何先前的减量.这种方法似乎是正确的,并出现在Herb Sutters 谈论原子论
在libc ++中,实现使用全内存屏障
template <class T>
inline T
increment(T& t) _NOEXCEPT
{
return __sync_add_and_fetch(&t, 1);
}
template <class T>
inline T
decrement(T& t) _NOEXCEPT
{
return __sync_add_and_fetch(&t, -1);
}
} // name
Run Code Online (Sandbox Code Playgroud)
这个决定有理由吗?它们之间是否有任何性能或安全差异?
c++ ×10
shared-ptr ×10
boost ×5
c++11 ×4
libc++ ×1
memory ×1
memory-leaks ×1
raii ×1
weak-ptr ×1