我正在开发一个C ++应用程序,我需要将std :: set的内容复制到std :: deque。类似于我在我的应用程序中所做的事情如下。 (这是简化版)
class A
{
public:
A(){};
~A() {};
void UpdateDataSet(std::set<C>& _setData);
private:
std::deque<C> deque_Data;//contains ohlc data for the symbol
};
void A::UpdateDataSet(std::set<C>& _setData)
{
std::set<C>::iterator itrSet = _setData.begin();
std::set<C>::iterator itrSetEnd = _setData.end();
while(itrSet != itrSetEnd)
{
deque_Data.push_back(*itrSet);
++itrSet;
}
}
int main()
{
A* pA = new A();
std::set<C> setData;
C mC1(5,10);
C mC2(10,20);
C mC2(30,40);
C.insert(mC1);
C.insert(mC2);
C.insert(mC3);
pA->UpdateDataSet(setData);
return 0;
}
这里C是一个包含两个整数的类。上面的代码工作正常,如我所料。但问题是当我使用valgrind memcheck对我的代码进行分析时,它指出了代码块附近可能丢失的数据
deque_Data.push_back(*itrSet);
valgrind输出如下。
==3469== 1,032,640 bytes in 180 blocks are possibly lost in loss record 1,337 of 1,346
==3469== at 0x4006355: operator new(unsigned int) (vg_replace_malloc.c:214)
==3469== by 0x46B92AF: __gnu_cxx::new_allocator<C*>::allocate(unsigned int, void const*) (new_allocator.h:88)
==3469== by 0x46B92E7: std::_Deque_base<C, std::allocator<C> >::_M_allocate_map(unsigned int) (stl_deque.h:424)
==3469== by 0x46B94F9: std::deque<C, std::allocator<C> >::_M_reallocate_map(unsigned int, bool) (deque.tcc:750)
==3469== by 0x46B960B: std::deque<C, std::allocator<C> >::_M_reserve_map_at_back(unsigned int) (stl_deque.h:1444)
==3469== by 0x46B96C5: std::deque<C, std::allocator<C> >::_M_push_back_aux(C const&) (deque.tcc:348)
==3469== by 0x46B9822: std::deque<C, std::allocator<C> >::push_back(C const&) (stl_deque.h:1045)
==3469== by 0x46B6B09: A::UpdateDataSet(std::set<C, std::less<C>, std::allocator<C> >&)
有人可以帮我查一下内存问题。这个valgrind输出真的意味着内存泄漏吗?
答案 0 :(得分:2)
你没有在主...的末尾做“删除pA”...
答案 1 :(得分:1)
有两个原因可以解释为什么deque分配的内存可能无法解除分配,假设标准库的正确实现:
reinterpet_cast
/ C风格的强制转换可以让您访问deque存储其私有成员的内存位置,例如:分配内存的指针。如果你以任何方式搞乱这些私有成员,deque可能无法释放其动态分配的内存,从而导致memleaks。通常情况下,这种激进行为会导致违反多种行为的行为,因此您会发现相当于崩溃的事情而不仅仅是回忆。deque*
并在免费存储/堆上分配了deque本身(见下文)。缺少原因A的析构函数的调用可能是以下一个或多个:
A()
)free()
而不是delete:free只释放内存但不调用任何析构函数。永远不要匹配新的和免费的,甚至更好的尝试不使用malloc / free与C ++对象,除非你非常小心并知道你做了什么(放置新...)goto
,因为如果你用goto违反了对象的生命周期边界,大多数编译器会发出错误。尽管如此,尽量不要在C ++中使用goto
,因为您可以使用其他功能。我可以在这里发送的唯一“跳跃”是longjmp
,这是一个不尊重范围边界的C功能,因此忽略了对析构函数调用的需求。 从不在C ++代码中使用longjmp
。如果有人能想到更多有关memleak的理由,缺少析构函数或其他人,请给我一个提示,我会编辑这个答案: - )
PS:我刚看到我错过了“看下面”的部分 - 如果你在A中有一个deque*
而不是deque
,那该怎么办?在这种情况下,A负责正确构建和破坏双端队列,这意味着
- 无论何时需要创建队列,都要调用new
- 至少在析构函数中调用delete
- 正确处理复制/移动分配和复制/移动构造
但是,如果您有一个deque*
并搞砸了指针处理,您应该看到另一个memleak,指向您将拥有的任何new deque
个电话。
答案 2 :(得分:1)
您的示例中缺少某些内容,没有内存泄漏。
我遵守并运行了此代码
#include <set>
#include <deque>
class C
{
public:
C (int a, int b)
: m_a (a)
, m_b (b)
{
}
bool operator <(const C& c) const
{
return m_a < c.m_a || (m_a == c.m_a && m_b < c.m_b);
}
private:
int m_a;
int m_b;
};
class A
{
public:
A(){};
~A() {};
void UpdateDataSet(std::set<C>& _setData);
private:
std::deque<C> deque_Data;//contains ohlc data for the symbol
};
void A::UpdateDataSet(std::set<C>& _setData)
{
std::set<C>::iterator itrSet = _setData.begin();
std::set<C>::iterator itrSetEnd = _setData.end();
while(itrSet != itrSetEnd)
{
deque_Data.push_back(*itrSet);
++itrSet;
}
}
int main()
{
A* pA = new A();
std::set<C> setData;
C mC1(5,10);
C mC2(10,20);
C mC3(30,40);
setData.insert(mC1);
setData.insert(mC2);
setData.insert(mC3);
pA->UpdateDataSet(setData);
delete pA;
return 0;
}
valgrind没有按预期报告任何可疑的内容