我有一个界面:
struct Interface{
Interface(const Interface &) = delete;
auto operator = (const Interface &) -> Interface & = delete;
virtual ~Interface() = 0;
};
我有一个实现:
struct Impl : public Interface {
Impl(const Impl &) = delete;
auto operator = (const Impl &) -> Impl & = delete;
bool m_is_borrowed{false};
std::weak_ptr<Pool> m_pool;
~Impl() {
if (m_is_borrowed) {
if (auto pool = m_pool.lock()) {
m_is_borrowed = false;
auto conn = std::unique_ptr<Interface>(this);
pool->m_objects.push_back(std::move(conn));
}
}
}
};
如代码所示,Pool
的成员类型为std::vector<std::unique_ptr<Interface>>
它还会创建Interface的实例:
auto impl = std::unique_ptr<Interface>(new Implementation());
m_objects.push_back(std::move(impl));
并为Pool
的用户提供一个:
auto get() -> std::unique_ptr<Interface> {
return std::move(m_objects.front());
}
所以我想做的是,删除Implementation
的实例时,检查是否从Pool
借来了,如果是这样,请将其发送回池中。如果它是池中的,请正常删除它。
将实例发送回池是可行的,但是在删除Pool
后尝试删除对象时,出现以下错误:
integration(46154,0x1003855c0) malloc: *** error for object 0x101900000: pointer being freed was not allocated
integration(46154,0x1003855c0) malloc: *** set a breakpoint in malloc_error_break to debug
具有以下堆栈跟踪:
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
* frame #0: 0x00007fff6418d23e libsystem_kernel.dylib`__pthread_kill + 10
frame #1: 0x00007fff64243c1c libsystem_pthread.dylib`pthread_kill + 285
frame #2: 0x00007fff640f61c9 libsystem_c.dylib`abort + 127
frame #3: 0x00007fff642056e2 libsystem_malloc.dylib`malloc_vreport + 545
frame #4: 0x00007fff642054a3 libsystem_malloc.dylib`malloc_report + 152
frame #5: 0x000000010000fa82 integration`Implementation::~Implementation(this=0x0000000101900000) at Implementation.cpp:14
frame #6: 0x000000010000a449 integration`std::__1::__vector_base<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> >, std::__1::allocator<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> > > >::~__vector_base() [inlined] std::__1::default_delete<Interface>::operator(this=0x0000000101800c58, __ptr=0x0000000101900000)(Interface*) const at memory:2285
frame #7: 0x000000010000a421 integration`std::__1::__vector_base<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> >, std::__1::allocator<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> > > >::~__vector_base() [inlined] std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> >::reset(this=0x0000000101800c58, __p=0x0000000000000000) at memory:2598
frame #8: 0x000000010000a3b0 integration`std::__1::__vector_base<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> >, std::__1::allocator<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> > > >::~__vector_base() [inlined] std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> >::~unique_ptr(this=0x0000000101800c58) at memory:2552
frame #9: 0x000000010000a3b0 integration`std::__1::__vector_base<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> >, std::__1::allocator<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> > > >::~__vector_base() [inlined] std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> >::~unique_ptr(this=0x0000000101800c58) at memory:2552
frame #10: 0x000000010000a3b0 integration`std::__1::__vector_base<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> >, std::__1::allocator<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> > > >::~__vector_base() [inlined] std::__1::allocator<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> > >::destroy(this=0x0000000101800a58, __p=0x0000000101800c58) at memory:1860
frame #11: 0x000000010000a358 integration`std::__1::__vector_base<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> >, std::__1::allocator<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> > > >::~__vector_base() [inlined] void std::__1::allocator_traits<std::__1::allocator<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> > > >::__destroy<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> > >(__a=0x0000000101800a58, __p=0x0000000101800c58) at memory:1727
frame #12: 0x000000010000a33c integration`std::__1::__vector_base<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> >, std::__1::allocator<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> > > >::~__vector_base() [inlined] void std::__1::allocator_traits<std::__1::allocator<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> > > >::destroy<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> > >(__a=0x0000000101800a58, __p=0x0000000101800c58) at memory:1595
frame #13: 0x000000010000a320 integration`std::__1::__vector_base<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> >, std::__1::allocator<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> > > >::~__vector_base() [inlined] std::__1::__vector_base<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> >, std::__1::allocator<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> > > >::__destruct_at_end(this=0x0000000101800a48, __new_last=0x0000000101800c50) at vector:413
frame #14: 0x000000010000a297 integration`std::__1::__vector_base<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> >, std::__1::allocator<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> > > >::~__vector_base() [inlined] std::__1::__vector_base<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> >, std::__1::allocator<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> > > >::clear(this=0x0000000101800a48) at vector:356
frame #15: 0x000000010000a27f integration`std::__1::__vector_base<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> >, std::__1::allocator<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> > > >::~__vector_base(this=0x0000000101800a48) at vector:441
frame #16: 0x000000010000a235 integration`std::__1::vector<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> >, std::__1::allocator<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> > > >::~vector(this=0x0000000101800a48 size=2) at iterator:1425
frame #17: 0x0000000100002395 integration`std::__1::vector<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> >, std::__1::allocator<std::__1::unique_ptr<Interface, std::__1::default_delete<Interface> > > >::~vector(this=0x0000000101800a48 size=2) at iterator:1425
frame #18: 0x0000000100002478 integration`Pool::~Pool(this=0x00000001018009d8) at Pool.cpp:17
frame #19: 0x0000000100002565 integration`Pool::~Pool(this=0x00000001018009d8) at Pool.cpp:15
frame #20: 0x0000000100167029 integration`std::__1::__shared_ptr_emplace<Pool, std::__1::allocator<Pool> >::__on_zero_shared(this=0x00000001018009c0) at memory:3656
frame #21: 0x000000010000cc01 integration`std::__1::shared_ptr<Pool>::~shared_ptr() [inlined] std::__1::__shared_count::__release_shared(this=0x00000001018009c0) at memory:3490
frame #22: 0x000000010000cbb7 integration`std::__1::shared_ptr<Pool>::~shared_ptr() [inlined] std::__1::__shared_weak_count::__release_shared(this=0x00000001018009c0) at memory:3532
frame #23: 0x000000010000cbb7 integration`std::__1::shared_ptr<Pool>::~shared_ptr(this=0x00007ffeefbfe1a0) at memory:4468
frame #24: 0x0000000100002da5 integration`std::__1::shared_ptr<Pool>::~shared_ptr(this=0x00007ffeefbfe1a0) at memory:4466
frame #25: 0x0000000100165d1f integration`____C_A_T_C_H____T_E_S_T____0() at Pool.cpp:30
frame #26: 0x00000001000516e3 integration`Catch::TestInvokerAsFunction::invoke(this=0x0000000100702b90) const at catch.hpp:11605
frame #27: 0x000000010003e277 integration`Catch::TestCase::invoke(this=0x0000000101800760) const at catch.hpp:11506
frame #28: 0x000000010003e16d integration`Catch::RunContext::invokeActiveTestCase(this=0x00007ffeefbff308) at catch.hpp:10365
frame #29: 0x0000000100039abb integration`Catch::RunContext::runCurrentTest(this=0x00007ffeefbff308, redirectedCout="", redirectedCerr="") at catch.hpp:10339
frame #30: 0x0000000100037387 integration`Catch::RunContext::runTest(this=0x00007ffeefbff308, testCase=0x0000000101800760) at catch.hpp:10115
frame #31: 0x0000000100042c39 integration`Catch::(anonymous namespace)::runTests(config=std::__1::shared_ptr<Catch::Config>::element_type @ 0x0000000101800228 strong=4 weak=1) at catch.hpp:10667
frame #32: 0x00000001000417e6 integration`Catch::Session::runInternal(this=0x00007ffeefbff780) at catch.hpp:10862
frame #33: 0x00000001000414c5 integration`Catch::Session::run(this=0x00007ffeefbff780) at catch.hpp:10819
frame #34: 0x000000010007ef8a integration`int Catch::Session::run<char>(this=0x00007ffeefbff780, argc=2, argv=0x00007ffeefbff8f8) at catch.hpp:10565
frame #35: 0x000000010007eed2 integration`main(argc=2, argv=0x00007ffeefbff8f8) at catch.hpp:14318
frame #36: 0x00007fff6404ded9 libdyld.dylib`start + 1
frame #37: 0x00007fff6404ded9 libdyld.dylib`start + 1
逐步调试显示,Pool
被销毁时m_is_borrowed
为假,因此不会创建新的unique_ptr实例。是什么原因导致此问题?
答案 0 :(得分:2)
app.post("/refreshToken", function(req, res){
if(!req.session.uid) return res.send({suc:0});
admin.auth().verifyIdToken(req.body.newToken || "").then(function(decodedToken) {
if(req.session.uid == decodedToken.uid){
req.session.token = req.body.newToken;
return res.send({suc:1});
}
})
.catch(function(error) {
res.send({suc:0});
});
});
您实际上并没有auto get() -> std::unique_ptr<Interface> {
return std::move(m_objects.front());
}
从上面的池中删除指针。在调用erase
之前和之后检查size()
中的m_objects
,您会发现大小前后完全相同。您将在get()
处留空unique_ptr
。
请考虑以下内容:
front()
或更有效地,让它从auto get() -> std::unique_ptr<Interface> {
auto rv = std::move(m_objects.front());
m_objects.erase(m_objects.begin());
return rv;
}
中选择一个,因为矢量将不必移动其数据:
back()
问题二:
auto get() -> std::unique_ptr<Interface> {
auto rv = std::move(m_objects.back());
m_objects.pop_back();
return rv;
}
您在此处创建一个~Impl() {
if (m_is_borrowed) {
if (auto pool = m_pool.lock()) {
m_is_borrowed = false;
auto conn = std::unique_ptr<Interface>(this);
pool->m_objects.push_back(std::move(conn));
}
}
}
,并为其拥有unique_ptr
的所有权。当this
返回时,~Impl()
指向的内存将(通常)为this
d。 free
现在拥有一个无效的指针,并且对该指针执行unique_ptr
时,任何事情都会发生。
这里有一个例子来说明。我已将delete
替换为unique_ptr
,其中已有一些日志记录。 smart
的每个实例还具有一个可以跟踪的smart
。
id
可能的输出:
#include <iostream>
#include <vector>
template<typename T>
struct smart {
static int instance;
int id;
T* ptr;
smart() : id(++instance), ptr(nullptr) {}
smart(T* p) : id(++instance), ptr(p) {
std::cout << "smart("<<id<<") ctor got ptr: " << std::boolalpha << (ptr!=nullptr) << "\n";
}
smart(const smart&) = delete;
smart(smart&& o) : id(++instance), ptr(std::exchange(o.ptr, nullptr)) {
std::cout << "smart("<<id<<") move ctor from "<<o.id<<"\n";
}
smart& operator=(const smart&) = delete;
smart& operator=(smart&& o) {
delete ptr;
ptr = std::exchange(o.ptr, nullptr);
std::cout << "smart("<<id<<") move assign from "<<o.id<<"\n";
}
~smart() {
std::cout << "~smart("<<id<<") real delete: " << std::boolalpha << (ptr!=nullptr) << "\n";
delete ptr;
}
};
template<typename T>
int smart<T>::instance = 0;
struct try_me;
std::vector<smart<try_me>> pool;
struct try_me {
try_me() { std::cout << "try_me\n"; }
~try_me() {
std::cout << "~try_me -- start --\n";
auto tmp = smart<try_me>(this);
pool.push_back(std::move(tmp));
std::cout << "~try_me -- end --\n";
}
};
int main() {
pool.emplace_back(new try_me);
std::cout << "--------------\n";
pool.pop_back();
std::cout << "--------------\n";
}