删除移动到容器中的对象时,SIGABRT

时间:2019-02-15 11:38:49

标签: c++ c++11

我有一个界面:

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实例。是什么原因导致此问题?

1 个答案:

答案 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";
}