views:

549

answers:

2
+9  A: 

You cannot use a "templated typedef", but you can use a convenience class/struct with an inner type:

template<typename T>
struct TypeHelper{
    typedef std::vector<T,gc_allocator<T> > Vector;
};

and then use in your code

TypeHelper<MyType>::Vector v;
TypeHelper<MyType>::Vector::iterator it;

And something similar for the map:

template<typename K,typename V>
struct MapHelper{
    typedef std::map<K, V, gc_allocator<K,V> > Map;
};

EDIT - @Vijay: I don't know if there's another possible workaround, that's how I would do it; a macro might give you a more compact notation, but personally I wouldn't like it:

#define GCVECTOR(T) std::vector<T,gc_allocator<T> >

EDIT - @chmike: Please note that the TypeHelper solution does not require you to redefine constructors!

Paolo Tedesco
Is there any other work-around available ?
Warrior
Yeap, there is. Inheritance is much neater is this very case.
sharptooth
@sharptooth: it's true that inheritance in this case gives you the best notation and avoids the use of a macro, but its usage is debatable, as pointed out in the comments to your answer.
Paolo Tedesco
I'm patiently waiting for any proof of potential problems.
sharptooth
I'll pick answer with the macro since it is the "best" solution. Both other solutions (inheritance or inner class/struct) require to redefine constructors. The macro would be used in typedef instructions.
chmike
@sharptooth: You've got proof already. "The standard doesn't guarantee that it'll behave as expected." It might work on every C++ compiler in existence today, but not in the version released next year. If you choose to rely on undefined behavior, thatis your choice, but the burden of proof is yours
jalf
@jalf. Reasonable. Definitely from the "works, but proceed with care" department.
sharptooth
You could add in your answer that template typedefs (aka template aliases) will be included in C++0x (however, it's not supported by gcc yet) http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf.
Luc Touraille
Thanks. I've added an example.I also show why the macro method is bogus and should not be used. Learned by experience. ;)
chmike
+3  A: 

You can publicly inherit:

template<class T>
class gc_vector<T> : public std::vector<T, gc_allocator<T> >
{
    public:
    // You'll have to redeclare all std::vector's constructors here so that
    // they just pass arguments to corresponding constructors of std::vector
};

This solves your problem completely. The derived type can be used everywhere where the base type can be used, and there's no implementation overhead with any decent compiler.

The fact that std::vector has non-virtual destructor might lead to undefined behaviour according to C++ standard if you ever try to delete a derived class variable through a pointer to base class variable.

In real world this shouldn't matter in this particular case - the derived class has nothing new added compared to the base class and therefore the destructor for the derived class just calls the destructor for the base class. Proceed with paranoia, port carefully anyway.

If you never allocate this class variables on heap (and it's typical to allocate vector variables on stack and as members of other classes) the non-virtual destructor problem doesn't affect you.

sharptooth
There is the problem that vectors are not designed to be derived from, as they lack a virtual destructor.
anon
True, but it doesn't matter in this particular case, since the derived type has exactly the same set of meber variables as the base type.
sharptooth
It matters if he deletes a pointer to a base that points to a derived as he is then off in undefined behaviour land.
anon
Nope, it doesn't matter in this case. The derived has no new data members compared to the base, so there's no difference between delete for Base* and Derived*. The derived constructor just calls the base constructor anyway.
sharptooth
hi sharptooth, what if he creates some memory in the derived constructor and deletes a pointer to a base that points to a derived class. Memory leak isnt it. I think, your solution fits perfectly for the current question, but its not robust.
Warrior
Also Sharptooth, please mention that...no fiddling in derived class, i.e no resource acquisition. I vote u up.
Warrior
@sharptooth - it does matter - what you suggest may happen, but the standard says it is UB.
anon
Well, I hope that the standard is not the replacement for logic and common sense. Can you show an example of why this very case may cause problems?
sharptooth
What about constructors ? Regarding memory leaks, note that this is for a garbage collector use. As long as gc_allocator is used, there is no memory leak (assuming specification is correct :) )
chmike
You'll have to redeclare all constructors so that they call corresponding vector's constructors.
sharptooth
There is no common sense in relying on undefined behavior. It's inherently unportable regardless of what one implementation happens to do. So yes, the standard is a replacement for "common sense" in this case.
Dan Olson
Yeap, I completely agree, but I'd like to see an example of what can go wrong in this particular case.
sharptooth
As long as nothing causes the gc_vector to have a vtable or any data, then this should fall into the 'not to standard, but you can certainly get away with it' category. If anything can cause gc_vector to have data or vtable, then deleting via base pointer is gonna kill you.
Michael Kohne
It's hard to give an example of undefined behavior. A conforming implementation could delete the contents of your hard disk if it felt like it. If you try it on all reasonable systems and it works as expected, feel free to use it knowing it's undefined. As a rule, though, I'd steer clear of UB.
Dan Olson
@Michael Not kill, just a memory leak in certain cases.
sharptooth
The need to redefine constructors (and I guess some typedefs too) in both solutions leads to the conclusion that the macro is the "best" solution.
chmike
Debugging code with macros is much harder compared to code with templates.
sharptooth
Macros are definitely not the best solution. Avoid themn. I'd go with the struct/typedef wrapper, and suffer the few characters extra typing, but in practice, sharptooths suggestion works too (although I'd only do it if I was sure I'd call the base class' destructor directly.
jalf
@sharptooth, no, he said kill, not memory leak, because that's what might happen. You can't in general be sure that the only function of a destructor is to release allocated memory. It might have important side effects. And so, it might corrupt the app state if the correct dtor is not called.
jalf
Yeap, reasonable.
sharptooth