Programmers using boost::shared_ptr need to avoid cycles so that a resource leak is not created. The general advice is to use a boost::weak_ptr in the cases where such a cycle might be created. However doing so creates a gap in intention where one might have preferred to use a shared_ptr but didn't do so only because of the cycle problem.
It seems to me, though, that it should be possible to create a special kind of shared_ptr which avoids the cycle problem by linking the reference count of all the pointers in the cycle. And since I can think of a way to do it, I'm wondering does such a thing exists.
For the sake of proving that I'm not crazy, or perhaps that I am, I offer the following poorly thought out and ugly proof of concept:
#define BOOST_NO_MEMBER_TEMPLATE_FRIENDS
#include <boost/shared_ptr.hpp>
#include <iostream>
template <typename T>
struct shared_count_ptr
{
boost::shared_ptr<T> innerPtr;
template <typename TT>
void link( boost::shared_ptr<T> & sharedPtr, boost::shared_ptr<TT> & linked )
{
innerPtr = sharedPtr;
innerPtr.pn = linked.pn;
}
};
struct Hand;
struct Arm
{
Arm() { std::cout << "Creating Arm\n"; }
~Arm() { std::cout << "Destroying Arm\n"; }
shared_count_ptr<Hand> hand;
};
struct Hand
{
Hand() { std::cout << "Creating Hand\n"; }
~Hand() { std::cout << "Destroying Hand\n"; }
shared_count_ptr<Arm> arm;
};
int main()
{
boost::shared_ptr<Arm> savedArm;
std::cout << "Scope 0 entered\n";
{
std::cout << "\tScope 1 entered\n" ;
boost::shared_ptr<Arm> arm( new Arm );
{
std::cout << "\t\tScope 2 entered\n";
boost::shared_ptr<Hand> hand( new Hand );
hand->arm.link( arm, arm->hand );
arm->hand.innerPtr = hand;
savedArm = arm;
}
std::cout << "\t\tScope 2 exited\n";
}
std::cout << "\tScope 1 exited\n";
std::cout << "\tScope 0 about to exit\n";
return 0;
}
The general concept being that in the eyes of the imaginary shared_count_ptr, the Arm and Hand are the effectively same object.
So:
Does such a think already exist in boost?
If not, is it because it's a terrible idea? (Or did I just come up with something clever?)
Here's a simple test. Create a complete graph on 17 vertices, such that the program points only to vertex 0. Start removing edges at random. Does your idea work? (Spoiler: it doesn't).
I would imagine you could do something along those lines. However, in such a structure every pointer A needs to be aware about every single other pointer B, such that either B can be reached from A or vice versa. I don't see how this can possibly scale to more than a tiny number of interconnected pointers.
It would seem that if you want to support circular references without any help from the programmer, you more or less need a full-blown garbage collector rather than a simple reference counting scheme (I'd love to be proved wrong on this).
Related
I have a Storage class that keeps a list of Things:
#include <iostream>
#include <list>
#include <functional>
class Thing {
private:
int id;
int value = 0;
static int nextId;
public:
Thing() { this->id = Thing::nextId++; };
int getId() const { return this->id; };
int getValue() const { return this->value; };
void add(int n) { this->value += n; };
};
int Thing::nextId = 1;
class Storage {
private:
std::list<std::reference_wrapper<Thing>> list;
public:
void add(Thing& thing) {
this->list.push_back(thing);
}
Thing& findById(int id) const {
for (std::list<std::reference_wrapper<Thing>>::const_iterator it = this->list.begin(); it != this->list.end(); ++it) {
if (it->get().getId() == id) return *it;
}
std::cout << "Not found!!\n";
exit(1);
}
};
I started with a simple std::list<Thing>, but then everything is copied around on insertion and retrieval, and I didn't want this because if I get a copy, altering it does not reflect on the original objects anymore. When looking for a solution to that, I found about std::reference_wrapper on this SO question, but now I have another problem.
Now to the code that uses them:
void temp(Storage& storage) {
storage.findById(2).add(1);
Thing t4; t4.add(50);
storage.add(t4);
std::cout << storage.findById(4).getValue() << "\n";
}
void run() {
Thing t1; t1.add(10);
Thing t2; t2.add(100);
Thing t3; t3.add(1000);
Storage storage;
storage.add(t3);
storage.add(t1);
storage.add(t2);
temp(storage);
t2.add(10000);
std::cout << storage.findById(2).getValue() << "\n";
std::cout << storage.findById(4).getValue() << "\n";
}
My main() simply calls run(). The output I get is:
50
10101
Not found!!
Although I was looking for:
50
10101
50
Question
Looks like the locally declared object t4 ceases to exist when the function returns, which makes sense. I could prevent this by dynamically allocating it, using new, but then I didn't want to manage memory manually...
How can I fix the code without removing the temp() function and without having to manage memory manually?
If I just use a std::list<Thing> as some suggested, surely the problem with t4 and temp will cease to exist, but another problem will arise: the code won't print 10101 anymore, for example. If I keep copying stuff around, I won't be able to alter the state of a stored object.
Who is the owner of the Thing in the Storage?
Your actual problem is ownership. Currently, your Storage does not really contain the Things but instead it is left to the user of the Storage to manage the lifetime of the objects you put inside it. This is very much against the philosophy of std containers. All standard C++ containers own the objects you put in them and the container manages their lifetime (eg you simply call v.resize(v.size()-2) on a vector and the last two elements get destroyed).
Why references?
You already found a way to make the container not own the actual objects (by using a reference_wrapper), but there is no reason to do so. Of a class called Storage I would expect it to hold objects not just references. Moreover, this opens the door to lots of nasty problems, including undefined behaviour. For example here:
void temp(Storage& storage) {
storage.findById(2).add(1);
Thing t4; t4.add(50);
storage.add(t4);
std::cout << storage.findById(4).getValue() << "\n";
}
you store a reference to t4 in the storage. The thing is: t4s lifetime is only till the end of that function and you end up with a dangling reference. You can store such a reference, but it isnt that usefull because you are basically not allowed to do anything with it.
Aren't references a cool thing?
Currently you can push t1, modify it, and then observe that changes on the thingy in Storage, this might be fine if you want to mimic Java, but in c++ we are used to containers making a copy when you push something (there are also methods to create the elements in place, in case you worry about some useless temporaries). And yes, of course, if you really want you can make a standard container also hold references, but lets make a small detour...
Who collects all that garbage?
Maybe it helps to consider that Java is garbage-collected while C++ has destructors. In Java you are used to references floating around till the garbage collector kicks in. In C++ you have to be super aware of the lifetime of your objects. This may sound bad, but acutally it turns out to be extremely usefull to have full control over the lifetime of objects.
Garbage? What garbage?
In modern C++ you shouldnt worry to forget a delete, but rather appreciate the advantages of having RAII. Acquiring resources on initialzation and knowing when a destructor gets called allows to get automatic resource management for basically any kind of resource, something a garbage collector can only dream of (think of files, database connections, etc.).
"How can I fix the code without removing the temp() function and without having to manage memory manually?"
A trick that helped me a lot is this: Whenever I find myself thinking I need to manage a resource manually I stop and ask "Can't someone else do the dirty stuff?". It is really extremely rare that I cannot find a standard container that does exactly what I need out of the box. In your case, just let the std::list do the "dirty" work.
Can't be C++ if there is no template, right?
I would actually suggest you to make Storage a template, along the line of:
template <typename T>
class Storage {
private:
std::list<T> list;
//....
Then
Storage<Thing> thing_storage;
Storage<int> int_storage;
are Storages containing Things and ints, respectively. In that way, if you ever feel like exprimenting with references or pointers you could still instantiate a Storage<reference_wrapper<int>>.
Did I miss something?...maybe references?
I won't be able to alter the state of a stored object
Given that the container owns the object you would rather let the user take a reference to the object in the container. For example with a vector that would be
auto t = std::vector<int>(10,0); // 10 element initialized to 0
auto& first_element = t[0]; // reference to first element
first_element = 5; // first_element is an alias for t[0]
std::cout << t[0]; // i dont want to spoil the fun part
To make this work with your Storage you just have to make findById return a reference. As a demo:
struct foo {
private:
int data;
public:
int& get_ref() { return data;}
const int& get_ref() const { return data;}
};
auto x = foo();
x.get_ref = 12;
TL;DR
How to avoid manual resource managment? Let someone else do it for you and call it automatic resource management :P
t4 is a temporary object that is destroyed at exit from temp() and what you store in storage becomes a dangling reference, causing UB.
It is not quite clear what you're trying to achieve, but if you want to keep the Storage class the same as it is, you should make sure that all the references stored into it are at least as long-lived as the storage itself. This you have discovered is one of the reasons STL containers keep their private copies of elements (others, probably less important, being—elimination of an extra indirection and a much better locality in some cases).
P.S. And please, can you stop writing those this-> and learn about initialization lists in constructors? >_<
In terms of what your code actually appears to be doing, you've definitely overcomplicated your code, by my estimation. Consider this code, which does all the same things your code does, but with far less boilerplate code and in a way that's far more safe for your uses:
#include<map>
#include<iostream>
int main() {
std::map<int, int> things;
int & t1 = things[1];
int & t2 = things[2];
int & t3 = things[3];
t1 = 10;
t2 = 100;
t3 = 1000;
t2++;
things[4] = 50;
std::cout << things.at(4) << std::endl;
t2 += 10000;
std::cout << things.at(2) << std::endl;
std::cout << things.at(4) << std::endl;
things.at(2) -= 75;
std::cout << things.at(2) << std::endl;
std::cout << t2 << std::endl;
}
//Output:
50
10101
50
10026
10026
Note that a few interesting things are happening here:
Because t2 is a reference, and insertion into the map doesn't invalidate references, t2 can be modified, and those modifications will be reflected in the map itself, and vise-versa.
things owns all the values that were inserted into it, and it will be cleaned up due to RAII, and the built-in behavior of std::map, and the broader C++ design principles it is obeying. There's no worry about objects not being cleaned up.
If you need to preserve the behavior where the id incrementing is handled automatically, independently from the end-programmer, we could consider this code instead:
#include<map>
#include<iostream>
int & insert(std::map<int, int> & things, int value) {
static int id = 1;
int & ret = things[id++] = value;
return ret;
}
int main() {
std::map<int, int> things;
int & t1 = insert(things, 10);
int & t2 = insert(things, 100);
int & t3 = insert(things, 1000);
t2++;
insert(things, 50);
std::cout << things.at(4) << std::endl;
t2 += 10000;
std::cout << things.at(2) << std::endl;
std::cout << things.at(4) << std::endl;
things.at(2) -= 75;
std::cout << things.at(2) << std::endl;
std::cout << t2 << std::endl;
}
//Output:
50
10101
50
10026
10026
These code snippets should give you a decent sense of how the language works, and what principles, possibly unfamiliar in the code I've written, that you need to learn about. My general recommendation is to find a good C++ resource for learning the basics of the language, and learn from that. Some good resources can be found here.
One last thing: if the use of Thing is critical to your code, because you need more data saved in the map, consider this instead:
#include<map>
#include<iostream>
#include<string>
//Only difference between struct and class is struct sets everything public by default
struct Thing {
int value;
double rate;
std::string name;
Thing() : Thing(0,0,"") {}
Thing(int value, double rate, std::string name) : value(value), rate(rate), name(std::move(name)) {}
};
int main() {
std::map<int, Thing> things;
Thing & t1 = things[1];
t1.value = 10;
t1.rate = 5.7;
t1.name = "First Object";
Thing & t2 = things[2];
t2.value = 15;
t2.rate = 17.99999;
t2.name = "Second Object";
t2.value++;
std::cout << things.at(2).value << std::endl;
t1.rate *= things.at(2).rate;
std::cout << things.at(1).rate << std::endl;
std::cout << t1.name << "," << things.at(2).name << std::endl;
things.at(1).rate -= 17;
std::cout << t1.rate << std::endl;
}
Based on what François Andrieux and Eljay have said (and what I would have said, had I got there first), here is the way I would do it, if you want to mutate objects you have already added to a list. All that reference_wrapper stuff is just a fancy way of passing pointers around. It will end in tears.
OK. here's the code (now edited as per OP's request):
#include <iostream>
#include <list>
#include <memory>
class Thing {
private:
int id;
int value = 0;
static int nextId;
public:
Thing() { this->id = Thing::nextId++; };
int getId() const { return this->id; };
int getValue() const { return this->value; };
void add(int n) { this->value += n; };
};
int Thing::nextId = 1;
class Storage {
private:
std::list<std::shared_ptr<Thing>> list;
public:
void add(const std::shared_ptr<Thing>& thing) {
this->list.push_back(thing);
}
std::shared_ptr<Thing> findById(int id) const {
for (std::list<std::shared_ptr<Thing>>::const_iterator it = this->list.begin(); it != this->list.end(); ++it) {
if (it->get()->getId() == id) return *it;
}
std::cout << "Not found!!\n";
exit(1);
}
};
void add_another(Storage& storage) {
storage.findById(2)->add(1);
std::shared_ptr<Thing> t4 = std::make_shared<Thing> (); t4->add(50);
storage.add(t4);
std::cout << storage.findById(4)->getValue() << "\n";
}
int main() {
std::shared_ptr<Thing> t1 = std::make_shared<Thing> (); t1->add(10);
std::shared_ptr<Thing> t2 = std::make_shared<Thing> (); t2->add(100);
std::shared_ptr<Thing> t3 = std::make_shared<Thing> (); t3->add(1000);
Storage storage;
storage.add(t3);
storage.add(t1);
storage.add(t2);
add_another(storage);
t2->add(10000);
std::cout << storage.findById(2)->getValue() << "\n";
std::cout << storage.findById(4)->getValue() << "\n";
return 0;
}
Output is now:
50
10101
50
as desired. Run it on Wandbox.
Note that what you are doing here, in effect, is reference counting your Things. The Things themselves are never copied and will go away when the last shared_ptr goes out of scope. Only the shared_ptrs are copied, and they are designed to be copied because that's their job. Doing things this way is almost as efficient as passing references (or wrapped references) around and far safer. When starting out, it's easy to forget that a reference is just a pointer in disguise.
Given that your Storage class does not own the Thing objects, and every Thing object is uniquely counted, why not just store Thing* in the list?
class Storage {
private:
std::list<Thing*> list;
public:
void add(Thing& thing) {
this->list.push_back(&thing);
}
Thing* findById(int id) const {
for (auto thing : this->list) {
if (thing->getId() == id) return thing;
}
std::cout << "Not found!!\n";
return nullptr;
}
};
EDIT: Note that Storage::findById now returns Thing* which allows it to fail gracefully by returning nullptr (rather than exit(1)).
From this question, I implement like this
Utils.h:
template<class T>
void SafeDeleteWithoutClass(T* &pVal) {
std::cout << __FUNCTION__ << std::endl;
delete pVal;
pVal = nullptr;
}
template<class T>
void SafeDeleteArrayWithoutClass(T* &pVal) {
std::cout << __FUNCTION__ << std::endl;
delete[] pVal;
pVal = nullptr;
}
main.cpp
#include "Utils.h"
struct Foo {
Foo() {std::cout << __FUNCTION__ << std::endl;}
~Foo() {std::cout << __FUNCTION__ << std::endl;}
}
int main()
{
Foo *pObj = new Foo();
SafeDeleteWithoutClass<Foo>(pObj2);
return 0;
}
It works well. But some guys in my team said it is not really better than macro. I don't know whether any example to prove this way is better than macro. Could you give me a hint?
It is not better then macro because you have no guarantee that it will save you from using pointer after deletion and deleting all things. It work practically the same. I guess that these guys just think it not better because it is the same. It is just written without using macro that's all.
Only advantage here is that you print some information on std::cout (but you can still do this in macro). And there are many disadventages here, to name few:
You can forget to call this function and have memory leak
Some one can still use pointer after it was deleted
It is hard to find if only one small object is leaking
You can call wrong function (e.g delete array for regular pointer)
Better to use std::shared_ptr<T> and std::unique_ptr. They will keep managing memory and make it clear who is the owner of memory (and memory ownership is important thing to consider on design of a class or whole project). But remember that smart pointers are not some miracle thing, you can still mess up some things. Take a look at this article to find out what not to do with them Top 10 dumb mistakes to avoid with C++ 11 smart pointers
I wanted to be able to have something like Java's interface semantics with C++. At first, I had used boost::signal to callback explicitly registered member functions for a given event. This worked really well.
But then I decided that some pools of function callbacks were related and it made sense to abstract them and register for all of an instance's related callbacks at once. But what I learned was that the specific nature of boost::bind and/or taking the value of this seemed to make that break. Or perhaps it was just the fact that the add_listener(X &x) method declaration changed the code that boost::bind generated.
I have a very rough understanding why the problem occurred and I think it's probably functioning correctly as per its design. I am curious: what should I have done instead? Surely there's a Right Way to do it.
Here's some example code:
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <iostream>
using namespace std;
struct X;
struct Callback
{
virtual void add_listener(X &x) = 0;
};
struct X
{
X() {}
X(Callback &c) { c.add_listener(*this); }
virtual void go() { cout << "\t'" << __PRETTY_FUNCTION__ << "'" << endl; }
};
struct CallbackReal : public Callback
{
virtual void add_listener(X &x)
{
f = boost::bind<void>(boost::mem_fn(&X::go), x);
}
void go() { f(); }
boost::function<void (void)> f;
};
struct Y : public X
{
Y() {}
Y(Callback &c) { c.add_listener(*this); }
virtual void go() { cout << "\t'" << __PRETTY_FUNCTION__ << "'" << endl; }
};
int main(void)
{
CallbackReal c_x;
CallbackReal c_y;
X x(c_x);
Y y(c_y);
cout << "Should be 'X'" << endl;
boost::bind<void>(boost::mem_fn(&X::go), x)();
cout << "Should be 'Y'" << endl;
boost::bind<void>(boost::mem_fn(&X::go), y)();
cout << "------------------" << endl;
cout << "Should be 'X'" << endl;
c_x.go();
cout << "I wish it were 'Y'" << endl;
c_y.go();
return 0;
}
Okay, I did not describe the problem completely. The title is misleading.
Oh, man. Downvote this one. I obviously haven't described the problem well and I think this ultimately boils down to mostly a syntactical error. :(
boost::bind takes its parameters by value and copies them. That means
f = boost::bind<void>(boost::mem_fn(&X::go), x);
will pass a copy of x, which will slice off the Y piece of it (if it was really a Y to begin with). To get virtual dispatch to work, you need to pass a pointer to boost::bind:
f = boost::bind(&X::go, &x);
(Note that you don't actually need mem_fn, or to explicitly write <void>, since boost::bind and argument deduction take care of those for you.)
Java interfaces don't specifically exist within C++. Closest you can get is pure abstract base classes. This is generally quite close enough.
The rest of your question is unrelated to interfaces. Java uses the Observer pattern for event connection and dispatch. The interface part is only mildly related because observers are required to obey specific interfaces (of course, since otherwise you wouldn't have any idea what to call).
Using boost::bind to create functors is actually an abstraction beyond interfaces and is thus a more generic solution. The observer pattern and functors are put together into signal/slot idiom/patterns implemented in various libraries like boost::signals, boost::signals2, and gtk++. The Qt version is quite different in mechanics but similar in concept.
So, what's this mean to help you understand what, why and where? I'd suggest starting with a search on what the Observer pattern is and try to write a few implementations.
I've seen my colleague do the second snippet quite often. Why is this? I've tried adding print statements to track the ctors and dtors, but both seem identical.
std::vector<ClassTest> vecClass1;
ClassTest ct1;
ct1.blah = blah // set some stuff
...
vecClass1.push_back(ct1);
std::vector<ClassTest> vecClass2;
vecClass2.push_back(ClassTest());
ClassTest& ct2 = vecClass2.back();
ct2.blah = blah // set some stuff
...
PS. I'm sorry if the title is misleading.
Edit:
Firstly, thank you all for your responses.
I've written a small application using std::move. The results are surprising to me perhaps because I've done something wrong ... would someone please explain why the "fast" path is performing significantly better.
#include <vector>
#include <string>
#include <boost/progress.hpp>
#include <iostream>
const std::size_t SIZE = 10*100*100*100;
//const std::size_t SIZE = 1;
const bool log = (SIZE == 1);
struct SomeType {
std::string who;
std::string bio;
SomeType() {
if (log) std::cout << "SomeType()" << std::endl;
}
SomeType(const SomeType& other) {
if (log) std::cout << "SomeType(const SomeType&)" << std::endl;
//this->who.swap(other.who);
//this->bio.swap(other.bio);
this->who = other.who;
this->bio = other.bio;
}
SomeType& operator=(SomeType& other) {
if (log) std::cout << "SomeType::operator=()" << std::endl;
this->who.swap(other.who);
this->bio.swap(other.bio);
return *this;
}
~SomeType() {
if (log) std::cout << "~SomeType()" << std::endl;
}
void swap(SomeType& other) {
if (log) std::cout << "Swapping" << std::endl;
this->who.swap(other.who);
this->bio.swap(other.bio);
}
// move semantics
SomeType(SomeType&& other) :
who(std::move(other.who))
, bio(std::move(other.bio)) {
if (log) std::cout << "SomeType(SomeType&&)" << std::endl;
}
SomeType& operator=(SomeType&& other) {
if (log) std::cout << "SomeType::operator=(SomeType&&)" << std::endl;
this->who = std::move(other.who);
this->bio = std::move(other.bio);
return *this;
}
};
int main(int argc, char** argv) {
{
boost::progress_timer time_taken;
std::vector<SomeType> store;
std::cout << "Timing \"slow\" path" << std::endl;
for (std::size_t i = 0; i < SIZE; ++i) {
SomeType some;
some.who = "bruce banner the hulk";
some.bio = "you do not want to see me angry";
//store.push_back(SomeType());
//store.back().swap(some);
store.push_back(std::move(some));
}
}
{
boost::progress_timer time_taken;
std::vector<SomeType> store;
std::cout << "Timing \"fast\" path" << std::endl;
for (std::size_t i = 0; i < SIZE; ++i) {
store.push_back(SomeType());
SomeType& some = store.back();
some.who = "bruce banner the hulk";
some.bio = "you do not want to see me angry";
}
}
return 0;
}
Output:
dev#ubuntu-10:~/Desktop/perf_test$ g++ -Wall -O3 push_back-test.cpp -std=c++0x
dev#ubuntu-10:~/Desktop/perf_test$ ./a.out
Timing "slow" path
3.36 s
Timing "fast" path
3.08 s
If the object is more expensive to copy after "set some stuff" than before, then the copy that happens when you insert the object into the vector will be less expensive if you insert the object before you "set some stuff" than after.
Really, though, since you should expect objects in a vector to be copied occasionally, this is probably not much of an optimization.
If we accept that your colleague's snippet is wise, because ClassTest is expensive to copy, I would prefer:
using std::swap;
std::vector<ClassTest> vecClass1;
ClassTest ct1;
ct1.blah = blah // set some stuff
...
vecClass1.push_back(ClassTest());
swap(ct1, vecClass1.back());
I think it's clearer, and it may well be more exception-safe. The ... code presumably allocates resources and hence could throw an exception (or else what's making the fully-built ClassTest so expensive to copy?). So unless the vector really is local to the function, I don't think it's a good idea for it to be half-built while running that code.
Of course this is even more expensive if ClassTest only has the default swap implementation, but if ClassTest doesn't have an efficient swap, then it has no business being expensive to copy. So this trick perhaps should only be used with classes known to be friendly, rather than unknown template parameter types.
As Gene says, std::move is better anyway, if you have that C++0x feature.
If we're worried about ClassTest being expensive to copy, though, then relocating the vector is a terrifying prospect. So we should also either:
reserve enough space before adding anything,
use a deque instead of a vector.
The second version benefits from moving the temporary. The first version is copying the temporary vector. So the second one is potentially faster. The second version has also potentially smaller peak memory requirements, the first version creates two objects one temporary and one copy of it and only then deletes the temporary. You can improve the first version by explicitly moving the temporary:
std::vector<ClassTest> vecClass1;
ClassTest ct1;
ct1.blah = blah // set some stuff
...
vecClass1.push_back(std::move(ct1));
You should probably ask your collegue to know exactly why, but we can still take a guess. As James pointed out, it might be a tad more efficient if the object is more expensive to copy once constructed.
I see advantages in both versions.
I like your collegue's snippet because: although there are 2 objects in both cases, they only co-exist for a very short period of time in the second version. There is only one object available for editing: this avoids the potential error of editing ct1 after push_back.
I like your personal snippet because: invoking push_back to add a second object potentially invalidates the reference ct2, inducing a risk of undefined behavior. The first snippet does not present this risk.
They are identical (as far as I can see). Maybe he or she does that as an idiomatic custom.
I am trying to figure out the memory consumption by my (C++) program using gprof. The program does not have a gui, it is entirely cli based.
Now, I am new to gprof, so I read a few tutorials, that taught me how to run gprof and spot time consumption.
However, I need to find out the memory consumption by a specific set of classes.
Say there is a program with many types, A, ..., Z. Now I want to run my program and see how many accumulated memory was used by objects of the classes A, E, I, O, U (for example).
Have you guys any ideas or pointers how I could approach this task?
I am not exclusively considering gprof, I am open for any (fos) software that gets the job done.
I have, of course, searched both google and stackoverflow.com for any answer to this problem, but either I use the wrong keywords or there is nobody having this problem out there.
Edit: Suggestions about doing this manually are obvious. Of course I could code it into the application, but its about a great deal of classes I would rather not change. Also, I want to have the total memory consumption, so I cannot only count all created objects, because I would have to track the size of the object individually.
Edit2: I went with a modification of DeadMG's suggestion, which I only have to inherit from. It works pretty well, so, if anybody has as similar problem, try this.
class GlobalObjectCounter {
public:
struct ClassInfo {
unsigned long created;
unsigned long destroyed;
unsigned short size;
ClassInfo() : created(0), destroyed(0), size(0) {}
ClassInfo(unsigned short _size) : created(0), destroyed(0), size(_size) {}
void fmt(std::ostream& os) {
os << "total: " << (this->created) << " obj = " << (this->created*this->size) << "B; ";
os << "current: " << (this->created-this->destroyed) << " obj = " << ((this->created-this->destroyed) * this->size) << "B; ";
}
};
protected:
static std::map<std::string,ClassInfo> classes;
GlobalObjectCounter() {}
public:
static void dump(std::ostream& os) {
for (std::map<std::string,ClassInfo>::iterator i = classes.begin(); i != classes.end(); ++i) {
os << i->first << ": ";
i->second.fmt(os);
os << "\n";
}
}
};
template <class T> class ObjectCounter : public GlobalObjectCounter {
private:
static ClassInfo& classInfo() {
static ClassInfo& classInfo = classes[std::string("") + typeid(T).name()];
classInfo.size = sizeof(T);
return classInfo;
}
public:
ObjectCounter() {
classInfo().created++;
}
ObjectCounter(ObjectCounter const& oc) {
classInfo().created++;
}
ObjectCounter& operator=(const ObjectCounter&) {}
~ObjectCounter() {
classInfo().destroyed++;
}
};
The map lookup is a bit nasty, I admit it, but I didn't have the nerve to take care of storing the iterator for each class. The main issue was that you would have to explicitly initialise it for each counted class. If you know how to do that better, tell me how.
I'm not aware of gprof even attempting to deal with questions of memory usage. The obvious alternative would be valgrind. If you only care about total memory usage, you could also do the job on your own (overload ::operator new and ::operator delete to track how much memory the program has requested). Of course, it's possible that you have some code that obtains memory by other means (e.g., directly calling something like sbrk), but that's fairly unusual. Those don't attempt to track statically allocated and/or stack usage though.
Trivial.
template<typename T> class Counter {
static int count = 0;
Counter() { count++; }
Counter(const Counter&) { count++; }
Counter& operator=(const Counter&) {}
~Counter() { count--; }
};
class A : Counter<A> {
static int GetConsumedBytes() {
return sizeof(A) * count;
}
};
If the use of A involves dynamic memory, then this solution can be improved on. You can also override the global operator new/delete.
GlibC provides statistics on heap memory allocation. Take a look at mallinfo. You could probably obtain statistics at various points during execution and get some kind of idea of how much memory is being used.