【发布时间】:2017-03-08 11:33:12
【问题描述】:
对于大多数人来说,这可能看起来像是重复的。但是我花了很多时间来解决这个问题。实现了 stackoverflow 和其他编码站点中给出的许多解决方案。最后我设法修复了它,但我仍然不知道我的旧实现有什么问题。
请帮助我找出导致我的旧代码、新代码、单元测试和 valgrind 错误的确切错误的原因。
注意:
- 我正在通过单元测试(Google 测试框架)测试我的代码。
- 使用 C++11 编译
- m_queue_ 是一个 std::vector
- 使用的 Google C++ 编码标准
测试:
- 队列有 2 个 SAPA 项(由新操作员创建)
- 按 id 删除第一个项目(队列现在只有一个)
- 删除唯一的项目 由它的 id 留下
- 在访问项目的 m_id_ 时,第二次删除似乎给出了 valgrind 错误
这是我的队列项目基类
class Item {
public:
Item() {
type = Type::kInvalid;
}
virtual ~Item() {}
Type type;
string m_id_ = string("");
};
这是子类
class SAPA : public Item {
public:
SAPA() { Item::type = Type::kSAPA; }
~SAPA() {}
};
旧代码用于在满足特定条件时删除项目 (RemoveIf)。导致 VALGRIND 问题。
This was proposed as a correct way to remove items from a vector in many posts.
void Queue::RemoveItems(const string& id) const {
vector<Item*>::iterator it = m_queue_.begin();
while (it != m_queue_.end()) {
Item* item = *it;
if (item == nullptr) {
continue;
}
if (RemoveIf(item, id)) {
delete item;
item = nullptr;
it = m_queue_.erase(it);
} else {
++it;
}
}
}
RemoveIf 函数
bool Queue::RemoveIf(Item* item,
const string& id) const {
**cout << id.c_str() << endl; <--- seems to cause the invalid read**
if (item->m_id_.compare(id) == 0) {
return true;
}
return false;
}
VALGRIND 输出显示大小为 8 的无效读取。抱歉,其中包含一些项目特定名称。
> ==21919== Invalid read of size 8
> ==21919== at 0x5880B90: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::c_str() const (in
> /usr/lib64/libstdc++.so.6.0.21)
> ==21919== by 0xEC416C: Queue::RemoveIf(network::multiplexer::Item*, blf::String const&) const (network_multiplexer_queue.cc:99)
> ==21919== by 0xEC3FFB: Queue::RemoveItems(blf::String const&) const (network_multiplexer_queue.cc:85)
> ==21919== by 0xEC4FDC: Queue::OnTimer() const (network_multiplexer_queue.cc:228)
> ==21919== by 0xFB05E0: (anonymous namespace)::NetworkMultiplexerTest_sapaTimeout_shouldBeHandled_successfully_Test::TestBody()
> (network_multiplexer_comm_test.cc:1201)
> ==21919== by 0x1232186: void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test,
> void>(testing::Test*, void (testing::Test::*)(), char const*) (in
> /home/sajith/cioffi/cioffi-linux/build/unit_tests)
> ==21919== by 0x122C547: void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test,
> void>(testing::Test*, void (testing::Test::*)(), char const*) (in
> /home/sajith/cioffi/cioffi-linux/build/unit_tests)
> ==21919== by 0x12124B7: testing::Test::Run() (in /home/sajith/cioffi/cioffi-linux/build/unit_tests)
> ==21919== by 0x1212D99: testing::TestInfo::Run() (in /home/sajith/cioffi/cioffi-linux/build/unit_tests)
> ==21919== by 0x1213444: testing::TestCase::Run() (in /home/sajith/cioffi/cioffi-linux/build/unit_tests)
> ==21919== by 0x1219F2E: testing::internal::UnitTestImpl::RunAllTests() (in
> /home/sajith/cioffi/cioffi-linux/build/unit_tests)
> ==21919== by 0x1233583: bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl,
> bool>(testing::internal::UnitTestImpl*, bool
> (testing::internal::UnitTestImpl::*)(), char const*) (in
> /home/sajith/cioffi/cioffi-linux/build/unit_tests)
> ==21919== Address 0x6d24a00 is 16 bytes inside a block of size 112 free'd
> ==21919== at 0x4C2A131: operator delete(void*) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
> ==21919== by 0xED3991: SAPA::~SAPA() (network_multiplexer_queue_item.h:82)
> ==21919== by 0xEC4045: Queue::RemoveItems(blf::String const&) const (network_multiplexer_queue.cc:86)
> ==21919== by 0xEC4FDC: OnTimer() const (network_multiplexer_queue.cc:228)
> ==21919== by 0xFB05E0: (anonymous namespace)::NetworkMultiplexerTest_sapaTimeout_shouldBeHandled_successfully_Test::TestBody()
> (network_multiplexer_comm_test.cc:1201)
> ==21919== by 0x1232186: void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test,
> void>(testing::Test*, void (testing::Test::*)(), char const*) (in
> /home/sajith/cioffi/cioffi-linux/build/unit_tests)
> ==21919== by 0x122C547: void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test,
> void>(testing::Test*, void (testing::Test::*)(), char const*) (in
> /home/sajith/cioffi/cioffi-linux/build/unit_tests)
> ==21919== by 0x12124B7: testing::Test::Run() (in /home/sajith/cioffi/cioffi-linux/build/unit_tests)
> ==21919== by 0x1212D99: testing::TestInfo::Run() (in /home/sajith/cioffi/cioffi-linux/build/unit_tests)
> ==21919== by 0x1213444: testing::TestCase::Run() (in /home/sajith/cioffi/cioffi-linux/build/unit_tests)
> ==21919== by 0x1219F2E: testing::internal::UnitTestImpl::RunAllTests() (in
> /home/sajith/cioffi/cioffi-linux/build/unit_tests)
> ==21919== by 0x1233583: bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl,
> bool>(testing::internal::UnitTestImpl*, bool
> (testing::internal::UnitTestImpl::*)(), char const*) (in
> /home/sajith/cioffi/cioffi-linux/build/unit_tests)
修复了以下 valgrind 问题 这是向后迭代并删除项目的新代码。
auto it = m_queue_.end();
while (it > m_queue_.begin()) {
it--;
Item* item = *it;
if (item == nullptr) {
continue;
}
if (RemoveIf(item, id)) {
delete item;
item = nullptr;
it = m_queue_.erase(it);
}
}
【问题讨论】:
-
if (RemoveIf(item, id))id 来自哪里?还是应该是RemoveIf(item, item->m_id_)? -
你展示了除了重要的东西之外的所有东西。什么是'id'?
-
是的,id 来自 item->m_id_。它通过一个循环传递,它将前面项目的 id 传递给函数。很抱歉缺少信息。因此,它会在第一次删除两项中的第一项。下次它将是队列中唯一的项目。谢谢!
-
刚刚用您可能的根本原因的信息更新了我的答案。