我在以下程序中观察到内存泄漏:
// 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;
==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)
答案 0 :(得分: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的{strike> badness 和invite all kinds of programmer error。
只需使用ptime
会员即可。说实话,我甚至不知道你为什么要复制year
,month
,day
和hour
字段,但是你在这里:
<强> 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();
}