gpt4 book ai didi

c++ 内存泄漏 - boost 库

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:47:05 25 4
gpt4 key购买 nike

我在以下程序中观察到内存泄漏:

// g++ -std=c++11 32_MyTime.cpp 
//
// valgrind --leak-check=full ./a.out
//


#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>

using namespace std;

class MyTime {
private:
int year;
int month;
int day;
int hour;
boost::posix_time::ptime *ptrTime;
void update() {
year = ptrTime->date().year();
month = ptrTime->date().month();
day = ptrTime->date().day();
hour = ptrTime->time_of_day().hours();
}
public:
~MyTime() {
if (ptrTime!=nullptr) delete ptrTime;
}
MyTime(int y, int m, int d, int h):year{y},month{m},day{d},hour{h} {
ptrTime = new boost::posix_time::ptime(
boost::gregorian::date(year, month, day),
boost::posix_time::hours(hour));
}
void addHours(int nHours) {
if (ptrTime!=nullptr) delete ptrTime;
ptrTime = new boost::posix_time::ptime(
boost::gregorian::date(year, month, day),
boost::posix_time::hours(hour+nHours));
update();
}
int getYear() const { return year; }
int getMonth() const { return month; }
int getDay() const { return day; }
int getHour() const { return hour; }
void set(int y, int m, int d, int h) {
if (ptrTime!=nullptr) delete ptrTime;
ptrTime = new boost::posix_time::ptime(
boost::gregorian::date(y, m, d),
boost::posix_time::hours(h));
update();
}
time_t getSecSince() const {
return (*ptrTime - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))).total_seconds();
}
const boost::posix_time::ptime* getPTime() const {
return ptrTime;
}
bool operator==(const MyTime& other) const {
return *ptrTime==*other.getPTime();
}
bool operator!=(const MyTime& other) const {
return !(*this == other);
}
bool operator<(const MyTime& other) const {
return *ptrTime < *(other.getPTime());
}
bool operator<=(const MyTime& other) const {
return *ptrTime <= *(other.getPTime());
}
bool operator>(const MyTime& other) const {
return *ptrTime > *other.getPTime();
}
bool operator>=(const MyTime& other) const {
return *ptrTime >= *other.getPTime();
}
};

void test() {

MyTime t1 {2016,5,21,17};
MyTime t2 {2016,5,22,10};

bool print = false;

if (print) {
cout << "From : " << *t1.getPTime() << endl; // Memory leak
cout << "To : " << *t2.getPTime() << endl; // Memory leak
}

cout << " t1 < t2 " << (t1<t2) << endl;
cout << " t1 > t2 " << (t1>t2) << endl;
cout << " t1 == t2 " << (t1==t2) << endl;
cout << " t1 < t1 " << (t1<t1) << endl;
cout << " t1 > t1 " << (t1>t1) << endl;
cout << " t1 == t1 " << (t1==t1) << endl;


while (t1<=t2) {
if (print)
cout << "> Time : " << *t1.getPTime() << " " << t1.getSecSince() << endl; // Memory leak
int s = t1.getSecSince();
t1.addHours(1);
}


}

int main() {
test();
}

我已经用valgrind分析了这个程序,这个类应该没有错误(从内存泄漏的角度来看)。

这条指令导致泄漏:

cout << "From : " << *t1.getPTime() << endl;  // Memory leak

但我不明白为什么。我假设boost库没有错误。它可能是一些复制构造函数(只是一种解释尝试)。

我该如何避免呢?

解决这个问题对我来说并不重要(代码只是为了调试),但重要的是理解为什么会发生这种情况以避免将来出现类似的错误。

编辑 代码没有内存泄漏。你必须打开打印才能得到泄漏:print = true;

编辑 2使用 print = true;

执行 Valgrind
==22204== 
==22204== HEAP SUMMARY:
==22204== in use at exit: 1,748 bytes in 31 blocks
==22204== total heap usage: 223 allocs, 192 frees, 38,751 bytes allocated
==22204==
==22204== LEAK SUMMARY:
==22204== definitely lost: 0 bytes in 0 blocks
==22204== indirectly lost: 0 bytes in 0 blocks
==22204== possibly lost: 619 bytes in 20 blocks
==22204== still reachable: 1,129 bytes in 11 blocks
==22204== suppressed: 0 bytes in 0 blocks
==22204== Rerun with --leak-check=full to see details of leaked memory
==22204==
==22204== For counts of detected and suppressed errors, rerun with: -v
==22204== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)

使用 print = true; 和更多的 cout 执行 Valgrind:

==22277== HEAP SUMMARY:
==22277== in use at exit: 1,748 bytes in 31 blocks
==22277== total heap usage: 79,279 allocs, 79,248 frees, 15,972,927 bytes allocated
==22277==
==22277== LEAK SUMMARY:
==22277== definitely lost: 0 bytes in 0 blocks
==22277== indirectly lost: 0 bytes in 0 blocks
==22277== possibly lost: 619 bytes in 20 blocks
==22277== still reachable: 1,129 bytes in 11 blocks
==22277== suppressed: 0 bytes in 0 blocks
==22277== Rerun with --leak-check=full to see details of leaked memory
==22277==
==22277== For counts of detected and suppressed errors, rerun with: -v
==22277== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)

用空 main 执行 Valgrind:

==22211== Memcheck, a memory error detector
==22211== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==22211== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==22211== Command: ./a.out
==22211==
==22211==
==22211== HEAP SUMMARY:
==22211== in use at exit: 0 bytes in 0 blocks
==22211== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==22211==
==22211== All heap blocks were freed -- no leaks are possible
==22211==
==22211== For counts of detected and suppressed errors, rerun with: -v
==22211== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)

最佳答案

好的。泄漏是虚假报告:

==20323== 72,704 bytes in 1 blocks are still reachable in loss record 1 of 1
==20323== at 0x4C2BBCF: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==20323== by 0x4EC21FF: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==20323== by 0x4010609: call_init.part.0 (dl-init.c:72)
==20323== by 0x401071A: call_init (dl-init.c:30)
==20323== by 0x401071A: _dl_init (dl-init.c:120)
==20323== by 0x4000D09: ??? (in /lib/x86_64-linux-gnu/ld-2.21.so)
==20323==

如您所见,它是从某个共享库初始化器分配的。如果您从 main 中删除所有代码,它会保持不变。

对于 print = true,我注意到泄漏的方面(这是设计使然)。


其次,正如其他人所说,不要做 new 事情。没有必要效仿 Java 和 invite all kinds of programmer error 缺点 .

只需使用 ptime 成员即可。老实说,我什至不明白为什么要重复 yearmonthdayhour字段,但你在这里:

Live On Coliru

我建议首先删除所有重复项:

Live On Coliru

#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>

class MyTime : public boost::posix_time::ptime {

using ptime = boost::posix_time::ptime;
using date = boost::gregorian::date;

public:
MyTime(short unsigned y, short unsigned m, short unsigned d, short unsigned h)
: ptime {date{y, m, d}, boost::posix_time::hours(h)}
{ }

void addHours(int nHours) { *this += boost::posix_time::hours(nHours); }

int getYear() const { return date().year(); }
int getMonth() const { return date().month(); }
int getDay() const { return date().day(); }
int getHour() const { return time_of_day().hours(); }

// instead of set, just assign `v = { 2016, 5, 22, 9 }`
time_t getSecSince() const { return (*this - ptime{date{1970, 1, 1}}).total_seconds(); }
};

void test() {

MyTime t1{ 2016, 5, 21, 17 };
MyTime t2{ 2016, 5, 22, 10 };

bool print = false;

if (print) {
std::cout << "From : " << t1 << std::endl;
std::cout << "To : " << t2 << std::endl;
}

std::cout << " t1 < t2 " << (t1 < t2) << std::endl;
std::cout << " t1 > t2 " << (t1 > t2) << std::endl;
std::cout << " t1 == t2 " << (t1 == t2) << std::endl;
std::cout << " t1 < t1 " << (t1 < t1) << std::endl;
std::cout << " t1 > t1 " << (t1 > t1) << std::endl;
std::cout << " t1 == t1 " << (t1 == t1) << std::endl;

while (t1 <= t2) {
if (print)
std::cout << "> Time : " << t1 << " " << t1.getSecSince() << std::endl;
int s = t1.getSecSince();
t1.addHours(1);
}
}

int main() {
test();
}

额外的替代设计

既然 MyTime 现在实际上只是对 ptime 的额外操作,为什么不呢:

Live On Coliru

using MyTime = boost::posix_time::ptime;
using MyDate = boost::gregorian::date;

MyTime make_hdate(short unsigned y, short unsigned m, short unsigned d, short unsigned h) {
return { MyDate{ y, m, d }, boost::posix_time::hours(h) };
}

MyTime addHours(MyTime const &mt, int nHours) {
return mt + boost::posix_time::hours(nHours);
}

time_t getSecSince(MyTime const &mt) {
return (mt - MyTime{ MyDate{ 1970, 1, 1 } }).total_seconds();
}

关于c++ 内存泄漏 - boost 库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37373944/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com