I have observed a memory leakage in the following program:
// 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();
}
I have analysed the program with valgrind
and the class should be error free (from the point of view of memory leakage).
This instruction causes the leakage:
cout << "From : " << *t1.getPTime() << endl; // Memory leak
but I do not understand why. I assume that the boost library has no error. It could be some copy constructor (just an explanation attempt).
How could I avoid it?
It is not vital for me to solve the issue (the code is there just for debugging), but it important to understand why it happens to avoid similar error in the future.
EDIT The code as it is has no memory leakage. You have to turn on the printing to get the leakage: print = true;
EDIT 2
Valgrind execution with 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)
Valgrind execution with print = true;
and a LOT MORE cout
:
==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)
Valgrind execution with empty main
:
==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)
Ok. The leak is a false report:
==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==
As you can see it's allocated from some shared library initializer. If you remove all code from main, it remains the same.
For print = true
I notice the leaked facets (that's by design).
Secondly, as others have said, don't do the new
thing. There is no need to emulate the badness of Java and invite all kinds of programmer error.
Just use a ptime
member already. To be honest I don't even see why you'd duplicate the year
, month
, day
and hour
fields at all, but here you are:
Live On Coliru
I'd suggest removing all duplication in the first place:
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();
}
Since MyTime
is really just extra operations on ptime
now, why not:
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();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With