- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
对于你们中的大多数人来说,这可能看起来像是重复的。但是我花了很多时间来解决这个问题。实现了 stackoverflow 和其他编码站点中给出的许多解决方案。最后我设法修复了它,但我仍然不知道我的旧实现有什么问题。
请帮助我找出导致确切错误的原因,查看我的旧代码、新代码、单元测试和 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);
}
}
最佳答案
编辑
经过你的澄清,真正的原因似乎已经很清楚了。
您将“id”作为 const string&
传递它传递对原始对象的引用而不是拷贝。因为它来自第一个物体,我猜你上面的某个地方有 const string& id = *m_queue_.begin()->m_id_;
然后您继续将其传递给 RemoveIf
.因为比较肯定会删除第一项,所以这发生在您的循环中。现在id
是对该项目中数据的悬挂引用。它在您的反向迭代版本中起作用的原因是第一项成为您删除的最后一项。删除它之后,没有其他东西看id
.您可能会更改分配 id
的代码行像string id = *m_queue_.begin()->m_id_;
.通过将其设为 string
而不是 string&
那时,您强制制作拷贝。该拷贝将有生命周期到范围结束。
结束编辑
您应该关注的一件事是标准库函数。特别是,你想要 vector::erase()
和 std::remove_if()
.您想要的删除版本是采用一对迭代器而不是一次删除一个迭代器的版本。当你调用它时,它看起来像 m_queue_.erase(XXXX, m_queue_.end())
。 .现在什么是 XXXX - 最终成为 remove_if
的返回值. remove_if 的参数是一对迭代器和一个一元谓词。 (即一个函数,它接受 const T&
作为 vector 中的任何内容,如果它应该被删除则返回 true。)返回值是一个迭代器,刚好超过未删除的项目的末尾。
在 c++11 中,这可能看起来像:
string id = "the_id_to_filter";
m_queue_.erase(std::remove_if(m_queue_.begin(), m_queue_.end(),
[&id](const Item* item) {
return item_.m_id_ == id;
});
在 c++11 之前的版本中,您可以将 lambda 替换为类似以下内容:
struct Filter {
Filter(const string& id) : id_(id) {}
string id_;
bool operator()(const Item* item) { return item.m_id_ == id_; }
};
然后你的电话看起来像这样:
string id = "the_id_to_filter";
m_queue_.erase(std::remove_if(m_queue_.begin(), m_queue_.end(), Filter(id)));
如果您的 vector 包含 nullptr
是有效的或者您不应该取消引用的其他值,将这些检查添加到谓词函数中。此外,如果 vector 拥有这些项目,您可能希望将其设为 vector<std::unique_ptr<Item>>
而不是 vector<Item*>
,如果你不这样做,那么使用 erase(remove_if) 习惯用法可能会泄漏。它还使您无需记住删除内容。
使用库函数将使您免于因循环中的一个错误而导致的沮丧和其他各种痛苦。
供引用:
关于c++ - 从 vector 中删除项目时出现 Valgrind 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40256546/
我希望 valgrind 在发现第一个错误时停止并退出。 请勿推荐 --vgdb-error=1 :它不会退出 valgrind。您必须连接 gdb 并从那里终止。 --db-attach : 在最近
有人可以快速解释 Valgrind 的工作原理吗?一个例子:它如何知道内存何时被分配和释放? 最佳答案 Valgrind 基本上在“沙箱”中运行您的应用程序。在此沙箱中运行时,它能够插入自己的指令来进
我有一个因 SIGSEGV 而崩溃的应用程序。 --20183-- VALGRIND INTERNAL ERROR: Valgrind received a signal 11 (SIGSEGV) -
我有一个因 SIGSEGV 而崩溃的应用程序。 --20183-- VALGRIND INTERNAL ERROR: Valgrind received a signal 11 (SIGSEGV) -
我想使用 valgrind 检查长时间运行的进程是否存在内存泄漏。我怀疑我所追求的内存泄漏可能仅在执行几个小时后才会发生。我可以在 valgrind 下运行应用程序并获取 valgrind 日志,但这
我想用 valgrind 检查一个长时间运行的进程是否有内存泄漏。我怀疑我所追求的内存泄漏可能仅在执行数小时后才会发生。我可以在 valgrind 下运行应用程序并获得 valgrind 日志,但这样
如何在不通过 valgrind 命令选项启动它的情况下对每个 Process 实例执行 valgrind memcheck。 有没有办法将监控选项保存在进程中,而不是每次都使用 valgrind 命令
我使用了“--trace-children=yes”选项,我还使用了“--trace-children-skip=patt1,patt2,...”选项(过滤掉噪音过程)。但它对我来说仍然很慢,我的多进
我从 Valgrind 得到以下日志: MPK ==5263== 4 bytes in 1 blocks are still reachable in loss record 1 of 84 ==52
如何在 Valgrind 抑制文件中添加注释? 我需要为一个大型项目维护一个 Valgrind 抑制文件。我们从我们链接到的工具中过滤无法修复的错误。随着工具的新版本发布,此文件可能需要随着时间的推移
我有一个大程序要运行。使用 valgrind 需要几个小时才能运行。我听说有一些东西可以让我们为程序中的特定函数调用 valgrind。其余程序将正常执行(没有 valgrind env)。 任何人都
我可以用 valgrind 检测整数溢出缺陷吗?里面的哪个工具可以做到这一点? 最佳答案 Valgrind 没有可以检测整数溢出的工具。 您可能会使用 gcc 选项捕获这些错误: -ftrapv Th
我有一个简单的程序: int main(void) { const char sname[]="xxx"; sem_t *pSemaphor; if ((pSemaphor = sem_o
如何让 Valgrind 准确显示错误发生的位置?我编译了我的程序(通过 PuTTy 在 Windows 机器上通过 Linux 终端)添加了 -g 调试选项。 当我运行 Valgrind 时,我得到
或者最好是全部,而不仅仅是我的代码?我的程序使用 Gtk、Loudmouth 和其他一些东西,而这两个(以及它们背后的一些,libgcrypto、libssl)本身导致了如此多的错误,以至于我无法检测
我想尝试使用 valgrind 进行一些堆损坏检测。通过以下腐败“单元测试”: #include #include #include int main() { char * c = (ch
我看过类似的问题here ,但我的问题是我没有编辑 default.supp 文件的权限。例如,Valgrind 中是否有任何忽略所有抑制文件的命令行选项? 最佳答案 在 Valgrind 3.10.
我在一个运行无限循环的程序上使用 valgrind。 由于memcheck在程序结束后显示内存泄漏,但由于我的程序有无限循环,它永远不会结束。 那么有什么方法可以强制从 valgrind 时不时地转储
我一直在尝试使用 valgrind 查找一些可疑的内存错误。 在被分析的程序甚至到达我希望分析的点之前,它会因为对 mmap 的调用开始失败而退出。当它不在 valgrind 下时,这些调用会成功。
由于 OpenSSL 使用未初始化的内存,因此对使用 openldap2 的 libldap 的程序进行 Valgrind 是一件苦差事。存在一个 --ignore-fn选项,但仅适用于 Valgri
我是一名优秀的程序员,十分优秀!