2

I have a C++ library (with over 50 source files) which uses a lot of STL routines with primary containers being list and vector. This has caused a huge code bloat and I would like to reduce the code bloat by creating a wrapper over the list and vector.

Shown below is my wrapper over std:: and the wrapped instances.

template<typename T>
class wlist
{
private:
    std::list<T> m_list;

public:

    // new iterator set.
    typedef typename std::list<T>::iterator iterator;
    typedef typename std::list<T>::const_iterator cIterator;
    typedef typename std::list<T>::reverse_iterator reverse_iterator;

    unsigned int size () { return m_list.size(); }
    bool empty () { return m_list.empty(); }
    void pop_back () { m_list.pop_back(); }
    void pop_front () { m_list.pop_front(); }
    void push_front (T& item) { m_list.push_front(item); }
    void push_back (T item) { m_list.push_back(item); }
    iterator insert(iterator position, T item) {m_list.insert(position,item);}
    bool delete_item (T& item);
    T back () { return (m_list.empty()) ? NULL : m_list.back();}
    T front () { return (m_list.empty()) ? NULL : m_list.front();}
    iterator erase(iterator item ) { return m_list.erase(item); }
    iterator begin() { return  m_list.begin(); }
    iterator end() { return m_list.end(); }
    reverse_iterator rbegin() { return  m_list.rbegin(); }
};

File A:

class label {

public:

int getPosition(void);
setPosition(int x);

private:

wlist<text*> _elementText; // used in place of list<text> _elementText;

}

File B:

class image {

private:

    void draw image() {
        wlist<label*>::iterator currentElement = _elementText.begin();
       ((label*)(*currentElement))->getPosition();    
        currentElement ++;
    }
}

My belief was that by wrapping the STL container, I would be able to reduce the code bloat but the reduction in code size seems to be insignificant while my motive to wrap the STL was to achieve a code reduction of roughly 20%.

1) By exposing the "wrapped" iterator, have I in-turn embedded STL into my client code thereby negating all the code saving that I was trying to do ???? 2) Have I chosen the right profiling method ????

Size before modification:

$ size libWrap.so

text:  813115
data: 99436
bss:  132704
dec : 1045255
hex:  ff307     

Size after modification:

$ size libWrap.so

text:  806607
data: 98780
bss:  132704
dec : 1038091
hex:  fd70b
skaffman
  • 398,947
  • 96
  • 818
  • 769
codebin
  • 285
  • 1
  • 4
  • 12
  • 10
    Perhaps I'm missing something, but if wlist ultimately holds a list, how will this reduce code bloat? You still have to instantiate the list template once per type used in wlist. – templatetypedef Feb 15 '11 at 20:58
  • @templatetypedef - will exposing a non templated wlist class help ??? – codebin Feb 15 '11 at 21:46
  • 5
    @codebin- It will, but then you lose all the benefits of templates (compile-time type safety, automatic inlining and optimization, etc.) There is no silver-bullet solution here - you're either going to pay for the templates you use, or you're not going to use templates. You can try to reduce the number of different template instantiations you have, but ultimately every instantiation will contribute to the code size. – templatetypedef Feb 15 '11 at 21:53
  • @templatetypedef - I agree with you. How can I completely eliminate local instances of wlist – codebin Feb 15 '11 at 22:03
  • @codebin- Why do you want to get rid of the iterator? If you're using a `std::list` and want to visit every element, you really don't have a choice other than to use the iterator. It's probably being instantiated internally anyway, so I doubt that getting rid of the iterator is going to help much/at all. – templatetypedef Feb 15 '11 at 22:10
  • @templatetypedef - How do you suggest I got go about reducing this code bloat introduced by STL usage. – codebin Feb 15 '11 at 23:41
  • 1
    For starters, I'd check whether or not this really is code bloat from the STL - are you compiling with optimizations turned on and debugging turned off? Second, the STL itself does lots of optimizations of this sort, so doing your own thing isn't likely to help. Like I said - the only guaranteed way to reduce template code size is to use fewer templates. If you want to shrink the code, then find spots where you don't need an STL container and replace it with something else. There really isn't a good, portable way to fix this problem otherwise. – templatetypedef Feb 15 '11 at 23:47
  • @templatetypedef - How about creating a shared library out of this STL wrapper and only exposing a template class. – codebin Feb 19 '11 at 00:39
  • @codebin- All that this is going to do is push where the code is out of the executable and into the shared library. You can't "cheat" and get template instantiations for free! If you have a template and instantiate it, you're going to get generated code. The only way to reduce code generated is to reduce the number of instantiations. – templatetypedef Feb 19 '11 at 00:43
  • @templatetypedef - How do I reduce stuff like this: list – codebin Feb 19 '11 at 02:23
  • 1
    @codebin, use functors and other stl agorithms (for example `for_each`). – Nim Mar 04 '11 at 09:50
  • What compiler are you using? Template "code bloat" was a real issue 15 years ago, but modern compilers/linkers are able to optimize it away. Unless you are using a *very* outdated compiler, I simply don't buy the code bloat problem. – Nemanja Trifunovic May 05 '11 at 14:03
  • My current template-heavy application is 5MB on `-O0 -g` and 200kB on `-O2`. What optimisation level (and other compile/link settings) are you using to get this "code bloat"? – Mark K Cowan Jul 15 '15 at 09:49

3 Answers3

5

Firstly, the interface offered by your wrapper is completely and totally disgusting. There's a reason that iterators exist, and it's because your implementation flat out doesn't work for non-pointer types. Returning and taking by value instead of by reference? A terrible design.

Secondly, you can never reduce the size of your program by introducing more code. Your wrapper still uses the STL list under the hood, so you're still instantiating all of those types. Most likely, the compiler just completely removed the whole lot.

Thirdly, you're not even doing an equivalent replacement, because you've replaced what used to be a list of values wth a list of pointers, introducing six million lifetime headaches and other problems.

Fourthly, even the idea of code bloat is quite ridiculous on the vast majority of platforms. I, of course, cannot psychically know that you are not working on some embedded platform with hardly any memory (although I doubt you would use many lists on such a platform) but on virtually every system, the size of the code itself is meaningless compared to other assets needed for the program to execute.

What you can do is try something like SCARY iterators or partial specializations for T*.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • 2
    Actually, you *can* reduce code bloat by introducing more code. You can specialize classes like `vector` for pointer types and hide away implementation in a base class that deals only with `void*`. This allows to have a single implementation for all (data-) pointer types and code bloat only in the clean, type-safe wrapper. – André Caron May 05 '11 at 13:21
  • @Andre: That is what I was referring to when I spoke of partial pointer specializations. However, I think you mis-understood me. Specializations only *change* a type, they don't introduce it. However, the questioner's wrapper *does* introduce new types. – Puppy May 05 '11 at 13:28
  • 1
    I'm not sure I misunderstood this sentence: "Secondly, you can *never* reduce the size of your program by introducing *more* code". Specializing a template class *is* introducing more code. – André Caron May 05 '11 at 13:56
  • 1
    @Andre Caron: It's introducing more literal source code, yes, but from the perspective of the compiler, it's not actually more code. The instantiation `Wrapper` still exists, just as it did before, you've just commanded the compiler to change the contents. – Puppy May 05 '11 at 22:58
2

I am trying to imagine why you are concerned with this. Why is it a problem?

My guess is that you have many ( hundreds? ) of different classes, and each one generates a copy of the templated containers.

If this is so and if it is necessary, then sit back and let the compiler do the tedious work for you.

If it is not necessary, then the problem seems likely to be that all your different classes are not necessary. There is a problem with your class design. You might have many different classes that differ only slightly. If the difference is so slight that the extra code generated to handle the difference seems out of proportion, then the different behavior might be better handled by code inside a single class.

ravenspoint
  • 19,093
  • 6
  • 57
  • 103
0

It seems that you want to pre-compile your templated wrapper once only in your library rather than have the compiler figure out the templated class every time it gets called. You can do this by moving your declaration from the header file (where it normally is for templated code) into your .cpp file. This also has the advantage that it reduces compilation times. There is a price in flexability in this approach, however, you have know from the beginnings the types that you want your class to work for (but you don't want the compiler to figure it out for you, anyway)

Putting templated code into a .cpp file will usually result in linker errors. To avoid these you need to expliciltly declaire the templates that you want the compiler to compile in the cpp file:

At the end of the .cpp file, you write something like

template class wlist<double>;
template class wlist<int>;

etc.

This instructs the compiler to compiler to compile these version of the class (and only these versions). This of cause reduces the flexibility of your library - if you call a wlist<complex> then you would get the linker errors.

See here for more info: http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12

I believe this is usually done to reduce compilation times - I imagine it will reduce code bloat too, but I have never used the technique for this reason and so never checked the size of my executable....

Tom
  • 5,219
  • 2
  • 29
  • 45
  • I'm honestly not sure what he's asking for. "Code bloat" would usually mean removing some unnecessary generated code from the binary, but templates don't add any unnecessary code. The compiler already instantiates only the required templates. Your technique makes the compiler go a lot faster, but in the end, the templates that get instantiated are exactly the same either way. – deong May 05 '11 at 13:36
  • @Deong - Thanks, I thought that might be the case... I have to admit that I have very little idea as to what the compiler "actually does". – Tom May 05 '11 at 13:43