1

I'll have a large struct containing basic types, STL objects (std::string) as well as objects of a library class (which I can't modify).

struct Info {
             string name;
             int  number;
             LibClass object;
             // ...
}

I'll want to stuff instances of this struct into a vector and then create a function to fill this vector.

vector<Info> list;

void addElement (string myName, int myNumber, LibClass myObject /*, ... */)
{
  Info newElement = { myName, myNumber, myObject /*, ... */};
  list.push_back(newElement);
}

The above code will fail, because the LibClass does not have an assigment operator specified which is needed by the vector implementation. The code will work if I change my struct (and the addElement function parameter) to hold a pointer to a LibClass object instead. But then I would have to do memory management outside of my function (create an LibClass object on the heap for every new element).

Next best thing is to do the memory management inside the addElement function by creating a copy of the given stack object on the heap, which would keep my calling code clean. But as this code is not part of another object, I have no destructor where I could free the memory again.

Is there a way to implement this without having to do memory allocation outside of this code AND without blowing this up to be a full featured factory class?

Update: I can't modify the library class, I'm not able to use C++11 or helper libs such as boost. The structs will basically be read-only inside the vector. Even the vector will be only filled once, then only read access will happen.

Chaos_99
  • 2,284
  • 2
  • 25
  • 29
  • Having a copy-constructor and copy-assignment operator for any non-trivial structure is almost always a good idea. – Some programmer dude Jan 14 '14 at 10:54
  • The declaration of the `newElement` indicates that you either have a copy constructor or move constructor for `LibClass`. In that case use `vector::emplace_back` if you can use C++11 – indeterminately sequenced Jan 14 '14 at 10:58
  • It really depend on what you want to do with your vector. One work arround is to use the `emplace_back` but you need to construct your LibClass object at the time you add it to the vector. But as @JoachimPileborg said is better to have a copy-ctor and copy-assignment ops. – mathk Jan 14 '14 at 10:59
  • Thanks for the sugestions. Unfortunatley, I have neither control over the library nor can I use C++11 (or additional libraries such as boost). I'll add this to the question. – Chaos_99 Jan 14 '14 at 11:20

2 Answers2

4

If I understood everything correctly, you may think of using std::shared_ptr<>. You'll be able to allocate the library dynamically, but freeing will be done automatically.

I thought of replacing LibClass object; with std::shared_ptr<LibClass> object; and instantiating LibClass inside addElement function. Info will be copyable, because shared_ptr can move and copy itself - each copy will still hold reference to the same LibClass instance. And on the other side, when you delete all instances of a single Info item (no matter how), the shared_ptr will take care of deleting LibClass instance as well. Think of shared_ptr as a way to dynamically create class and then leave it for automatic memory management.

Since std::shared_ptr<> is part of C++11, if you cannot use the latter, you can use its equivalent from Boost: boost::shared_ptr<>. If that's also not an option, you can implement a version of shared pointer yourself - an example.

Spook
  • 25,318
  • 18
  • 90
  • 167
  • Well, this looks promising. But while it's easy to make this a `vector >`, this alone won't solve my problem. (Or does it?) Seems I have to create a struct filled with a `shared_ptr` instead, which is a little more complicated. Do you mind giving an example for the simplified code above? – Chaos_99 Jan 14 '14 at 11:35
  • I thought of replacing `LibClass object;` with `std::shared_ptr object;` and instantiating LibClass inside `addElement` function. `Info` will be copyable, because `shared_ptr` can move and copy itself - each copy will still hold reference to the same `LibClass` instance. And on the other side, when you delete all instances of a single `Info` item (no matter how), the `shared_ptr` will take care of deleting `LibClass` instance as well. Think of `shared_ptr` as a way to dynamically create class and then leave it for automatic memory management. It's a win-win :) – Spook Jan 14 '14 at 11:44
  • Yes it is. Or would be. I've just realized that std::shared_ptr is also a C++11 addition to the standard. All I got is the auto_ptr. – Chaos_99 Jan 14 '14 at 11:48
  • AFAIR, if you cannot use C++11, You can always use `boost::shared_ptr`: http://www.boost.org/doc/libs/1_55_0/libs/smart_ptr/shared_ptr.htm – Spook Jan 14 '14 at 11:49
  • No, I also can not use boost, as (now) stated in the question above. No additional libraries, sorry. But auto_ptr should do the trick too, no? – Chaos_99 Jan 14 '14 at 11:52
  • Noone stops you from implementing something similar to `shared_ptr` by yourself (you can extract the shared_ptr from boost - that'll save you time). http://www.codeproject.com/Articles/15351/Implementing-a-simple-smart-pointer-in-c - for instance. I'm not sure how auto_ptr behaves when being copied - that's your biggest concern. – Spook Jan 14 '14 at 11:53
  • Ok, that's a bit more additional code than I anticipated, but it still seems to be the solutions with the least impact on my code. Would you like to include all that into your answer, so I can accept it? – Chaos_99 Jan 14 '14 at 12:03
  • Sure, modified the answer. – Spook Jan 14 '14 at 12:09
  • @Spook: How does `auto_ptr` behave when copied? _Very badly._ That's why it was deprecated in favour of `unique_ptr`. – Lightness Races in Orbit Jan 14 '14 at 12:48
1

You obviously already have a copy constructor, otherwise pass-by-value would fail. So vector growth ought not to be a problem (though you may have to avoid removing elements from the start or middle of the vector).

For construction, you may use emplace_back in C++11.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • Unfortunately, the compiler enforces the presence of an asignment function regardless of its actual use. `push_back` *will* fail. As emntioned above, I unfortunetely can't use C++11. – Chaos_99 Jan 14 '14 at 11:24
  • Yes, `push_back` will fail. That's why I suggested an alternative. :) There was a reason the alternative was added to C++11 so if you can't use it you may be SOL. – Lightness Races in Orbit Jan 14 '14 at 12:46