If developers hate Boost, what do they use?

This topic is 2180 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

I've been using Boost for quite some time now. For developing cross-platform code, it has been a huge help in reducing the need for platform-specific code. However, it comes with its own baggage, in terms of library size, slower compile times, and cryptic compiler errors.

In talking to game developers in other studios (AAA and indie), I've started to get the almost-universal impression that they hate Boost and wouldn't touch it for any serious (non-tool) development.

I can somewhat understand this, and I myself have been trying to reduce my use of Boost in order get a grip on compile and debug times, but there are some pieces of Boost that have been too useful to give up. For example, the threading library. Without it, I would have to write platform-specific code every time I created a new thread. Or the filesystem library, which lets me query files and directories without dealing with path separator differences and such.

So if most developers hate Boost, what do they use? Are they really just writing lots of platform-specific code for each game? Or are there lighter alternatives out there that work just as well for specific tasks?

Share on other sites
Boost is a big thing. Which libraries are you hearing that people hate?

Share on other sites
Usually we come up with low-level cross-platform implementations with a C-like interface, and then we wrap those with higher-level classes.

Share on other sites
Could be a bit of NIH syndrome.

Share on other sites
Also for an STL replacement, at my last job we used RDESTL.
For example, the threading library. Without it, I would have to write platform-specific code every time I created a new thread.
Usually we come up with low-level cross-platform implementations with a C-like interface, and then we wrap those with higher-level classes.
^QFE -- wrapping up the OS's native threading API in your own cross-platform wrapper shouldn't be more than a few hours work.
Or the filesystem library, which lets me query files and directories without dealing with path separator differences and such.
Most games don't use the filesystem very much. Also, native OS file-system APIs usually provide ways of using them that the usual cross-platform wrappers don't allow for, such as mapping a HDD file to a RAM address, so you can read the file using a pointer, as if it were already in RAM. Or, on Windows, when I use the CreateFile/ReadFileEx API, I can load huge data files using the OS's built-in background loading system and take advantage of the OS's file-caching abilities, which allows me to load multiple-GiB files in less than 33ms and without stalling.
Again, making your own wrapper for these APIs is only a few hours work.

Share on other sites
I don't use boost a lot, however quite often I am looking into its source as a background for my projects.
In general boost is very nice package, but sometimes its libs are useless. For example uBlas is completly useless comparing to BLAS and LAPACK therefore I would never use it in a real HPC project. But on the other hand Boost MPI graphs are really worth checking.

Share on other sites
Even standard STL (the one shipped with the compiler) is avoided in most places for the same reasons as boost, and often replaced by in house STL, EASTL or STL port.

Share on other sites
I don't use Boost. Never have.

Share on other sites
I wrote my own abstraction layer for my applications and it wasn't a big thing. The basic thread handling in windows and in linux isn't this much different.
The STL is used because of its simple usage. If I identify something for optimization it gets replaced with problem specific code.

Share on other sites
So it sounds like mostly professional game developers don't use any Boost because game consoles and other target platforms have unique development constraints, etc.?

I use boost + STL + C++11 extensively professionally in the domain of HPC for basically computational biology, so, you know, it is out there. Obviously, we use faster libraries for core things -- use a proprietary library that is faster than uBlas for linear algebra, faster libraries than boost::geometry, etc. But I don't think this is surprising -- boost is generic and free. It is great a first choice for just about any domain or use case targeted by one of its libraries (with a few exceptions imho), but for high-performance code running through the critical path of a commercial product you want to optimize for that product ... which I guess is what the game guys are saying, essentially.

However, people who aren't using boost, do you use shared_ptr? -- because I think I draw the line in the sand there. At this point, haven't written the keyword "delete" in a couple of years and am not interested in going back.

Share on other sites
Boost is a general, catch-all solution, solving mostly unimportant problems.

Being general, it lends itself well to prototypes that grow into production apps. Some parts are also quite lean.

But if going beyond the most basic MBA cargo culting, a company that employes even a semblance of decent programmers will find that providing alternative to boost is not that hard, or that boost doesn't offer sufficient advantage for anything non-generic.

Since apparently blas-like functionality tends to be used a lot by people here, it's one part I've never been all that impressed with. Graph library in particular is something I've found to be quite limiting and IMHO incorrectly designed for a general purpose library. It seems to assume stuff will fit into working memory or that computations will be small enough to not require interrupts or resumes or even progress reports, making the design a no-go from start.

Share on other sites

However, people who aren't using boost, do you use shared_ptr? -- because I think I draw the line in the sand there. At this point, haven't written the keyword "delete" in a couple of years and am not interested in going back.

Two relevant points:
a) All PC compilers have shipped shared_ptr under the std::tr1 namespace for a few years now. It's part of the standard and all at this point.
b) You'll run into the same problem with consoles that you do with Boost - the likelihood of finding an embedded C++11 compiler (or even TR1) is about nil.

Also, on embedded there's a good chance you won't be able to afford to manage memory in such a haphazard fashion. As someone mentioned earlier, embedded devices don't have the kind of general-purpose caches that PCs do - you'll often have to massage your data to eek every little bit of cache coherency, and that tends to put paid to traditional C++ memory management...

Share on other sites

Also, on embedded there's a good chance you won't be able to afford to manage memory in such a haphazard fashion. As someone mentioned earlier, embedded devices don't have the kind of general-purpose caches that PCs do - you'll often have to massage your data to eek every little bit of cache coherency, and that tends to put paid to traditional C++ memory management...

Couldn't you use the intrusive version of shared_ptr in this kind of situation?

Share on other sites

Couldn't you use the intrusive version of shared_ptr in this kind of situation?

What use is a smart pointer, if you are going to have to give up dynamic allocation entirely? Writing for the kind of resource constraints you face on a lot of embedded hardware is a whole other ballgame...

Now, there are plenty of mobile/embedded applications that can afford dynamic allocation and pointer chasing, but if you want to eke every last drop of performance, you have to make some sacrifices.

Share on other sites
First of all I have never used Boost. A little over a year ago I bought bjarne stroustrup's "the c++ programming language". I have learned a great deal about proper OO design since stroustrup spends a lot of time talking about design philosophy behind c++. I would be curious to know how well Boost follows this design philosophy? One design goal of c++ is to give the required tools to build powerful and extensive libraries. But often a library is built to go from point A to point D and fails to implement the B and C features properly b/c it's so obsessed with getting to D. Also in regards to the discussion about smart and shared_ptr, stroustrup devoted a section talking how to implement this ground up from the std lib. It's extremely useful but when I see people say to use a 3rd party lib to implement a feature this simple I think there a lack of understanding there. My experience has been that most commonly needed features are easily built on-top of the std lib (for this is what the std lib was designed for). Heck I even designed my own GC that is remarkably efficient and stable. All the parts to roll your own GC is there you just have to put them together. You will never learn how to do this if you use 3rd party libs all the time.

Share on other sites

In addition to the fact that Boost isn't a single library (it's a collection of quite a few libraries), I'd say the attitude in most games studios isn't "hate" as much as "know we can't actually use it."

Boost libraries often rely heavily on template tricks, for instance, which may not work well on the compilers that are available for certain console platforms. There's also a tendency in Boost code to rely on certain performance characteristics that are true of mainstream desktop/notebook CPUs, but not necessarily valid on mobile or console processors. (Cache behavior is a big deal on a lot of those CPUs, for instance, whereas PCs just continue to get better caches.)

The reality (for me at least) is that I'd love to use Boost in a few places, but it just doesn't hack it. There's also places where it's a fine prototyping solution (e.g. asio) but really heavy-duty applications need special-purpose designs to begin with.

QFT.

There are also other reasons companies will avoid boost, or even the standard library. Quite a few programmers who come out of college these days have either been bottlefed on Java (or similar languages) or learned "C with Classes but no standard library except std::cout". Both of which tend to have problems. In the Java case, you have a very large standard library which tends to... filter you from the implementations of many common algorithms and containers (the number of interviewees I've met who couldn't write a simple hash map is quite startling). The C with Classes case is even worse though, as many times the people who come from that background have delusional ideas about how "non-performant" the C++ standard library is, or other strange misconceptions.

Thus when these programmers go on to actually become industry professionals and start doing development work... guess what? Yeah.

Boost can also be quite complex to learn and figure out, it is a very large set of libraries, and some of them have some pretty wacky inter dependencies. It can make debugging annoying (at best) and the compiler error messages downright unhelpful in many cases. This isn't really the fault of Boost so much as it is just a problem with compilers, templates, and errors. Visual Studio has gotten a lot better about its error reporting in the last few years, but GCC still makes you want to murder your nearest open source advocate.

Share on other sites

First of all I have never used Boost. A little over a year ago I bought bjarne stroustrup's "the c++ programming language". I have learned a great deal about proper OO design since stroustrup spends a lot of time talking about design philosophy behind c++. I would be curious to know how well Boost follows this design philosophy?

Boost is the pinnacle of C++ OO design.

One design goal of c++ is to give the required tools to build powerful and extensive libraries. But often a library is built to go from point A to point D and fails to implement the B and C features properly b/c it's so obsessed with getting to D.[/quote]

That's kitchen sink philosphy which is frowned upon, but prevalent in Java world. it's unrelated to C++. A good library goes from A to D in simplest and most straightforward manner.

Also in regards to the discussion about smart and shared_ptr, stroustrup devoted a section talking how to implement this ground up from the std lib. It's extremely useful but when I see people say to use a 3rd party lib to implement a feature this simple I think there a lack of understanding there.[/quote]

Last standard was 15 years or so old, back in the time when concepts like shared_ptr weren't fully understood and the goal was to fix the language so far.

Recent revision of standard provides battle-tested concepts from boost as part of standard library and integral part of C++, including shared_ptr.

My experience has been that most commonly needed features are easily built on-top of the std lib (for this is what the std lib was designed for).[/quote]

Building a thread-safe, compiler and platform-portable shared pointer is incredibly difficult, unless one is willing to take a huge performance hit. The number of hidden pitfalls stemming from pre C++10's standardization of threading and memory model related concepts made it an excercise if frustration of trying to work around platform and compiler issues.

Even new '10 standard had to back down on some requirements for extended standard library since original boost's design proved too cumbersome to consistently implement.

Heck I even designed my own GC that is remarkably efficient and stable. All the parts to roll your own GC is there you just have to put them together.[/quote]

Does it work, without single change, on iPhone, gcc 2.95 - gcc 4+, LLVM, android, Sparc, embedded custom boards and OSX, proven by thousands of applications using it?

That is what boost gets you. It's also a fairly irrelevant problem for many, since most applications tend to be built around vertical platform-specific stacks, rather horizontal layer that C++ alone offers (which is minimal).

Boost isn't used in many cases since products are strictly single platform verticals and strongest point of Boost (cross-platform/-compiler portability) doesn't bring much.

It can however be quite beneficial in *nix centric server side, where APIs are mostly consistent, but one offsets deployment to typical package providers, while boost takes care of odd architectural quirks one finds in such places.

You will never learn how to do this if you use 3rd party libs all the time.[/quote]

No, but few of us have time to reinvent such low-level concepts. There simply isn't time, when your project deadlines are measured in hours, instead of months or years.

Share on other sites

Thus when these programmers go on to actually become industry professionals and start doing development work... guess what? Yeah.

You'll be hard pressed to get me to do anything in C++ without having boost, Qt or some other libraries as default.

Is something in these libraries interferring with my goals? Then they're out.

But the question shouldn't be whether to use boost or not. If should be whether OO-heavy ref-counted design is a good fit for problem being solved. Writing some UI and blob mangling app? It's fine. Writing HPC or real-time app? Throw it out. While you're at it, just use C.

There is no problem with libraries. They are fairly passive, boring and just tend to sit there. As for developers? Some are good, some are bad, some learn, some don't.

I have yet to see lack of libraries correlate with improved quality of design. In most cases, developers end up sticking with first thing they hack together that works. But I have seen Boost and related materials offer starting point for study into advanced areas of C++. For the motivated ones, it will provide a glimpse of what is possible or what others have done and serve as a starting point.

It's an optimization problem - not about code, but about hiring and management processes. Some developers, at a given time lack the necessary understanding. Whether they have boost or not, they lack required knowledge and more importantly experience to use alternatives. And considering most don't have a choice about their peers - let them use boost, at least they'll have some solid foundation, since what they'll invent by themselves will not be better.

Everything today is about time and deadlines. Given enough time, everyone could learn the in-depth problems. But a project that needs to be done this week - it's about trade offs. Seasoned developers will use alternatives if needed, the others simply don't know any (yet). Whether a library or NIH.

Share on other sites

At this point, haven't written the keyword "delete" in a couple of years and am not interested in going back.

I see this around a lot. I have to say, I choose to embrace the idea of keep using "delete" as I did in the last 20 years just to avoid having my code polluted with all that shared_ptr<Whatever> that makes C++ seriously fugly.

I think C++ needs a new keyword/operator for that, kind of what microsoft did using the "^" for .NET managed references in C++.

bool GraphTraverser::traverse(Node^ node);

instead of the ugly nonsense of:

bool GraphTraverser::traverse( shared_ptr<Node> node );

typedeffing shared_ptr<Node> into something else wont cut it either.

I'd rather write delete once (99% of the time it is in your destructor) than shared_ptr<blabla> over and over again having nightmares about circular references never cleaning up.

sorry to be OT, I had to rant

Share on other sites
As kunos said, there's nothing hard about writing [color=#0000ff]delete in object's destructor. If you're lazy then it's a good solution, but as GameDev article states: "smart pointers are only as smart as the person that is using them" (source: http://www.gamedev.net/blog/411/entry-2253348-smart-pointers-arent-always-so-smart/) and I choose not to use them at all.

In my opinion, Boost hardly provides anything useful. Possibly because I'm just noob at programming.

Share on other sites

As kunos said, there's nothing hard about writing delete in object's destructor.

There is also nothing good about writing 'delete' in your object's destructor.

In particular, if you use exceptions, writing 'delete' in your destructor does absolutely nothing if an exception were to be thrown during your constructor (typically, the most likely place for an exception to be thrown).

Share on other sites
It's not just about writing 'delete' somewhere; firstly there is a code mantaince issue of changing something and mistakes croping up.

Secondly if you are using shared_ptr as a replacement for delete then you are Doing It Wrong(tm) anyway; shared_ptr is for shared ownership and life time control of an object and only needs to be used when an object can be logically owned by multiple other objects and needs to go out of scope when all references to it are dropped. At which point you get into the area of thread safe reference counting of objects with shared ownership semantics which has just made life much harder and code more complex.
(They also allow you to route destruction via a specified function which can be very useful rather than having to make sure it happens by hand).

Circlar references are only a problem if you can't design software; if you are getting problems with passing shared_ptrs to everything then I think you need to go back and look at your design again because you are more than likely Doing It Wrong(tm) as it is illogical to have the lifetime of an object depend on another object which has its lifetime depend on the first object. Even using shared_ptr et al it is fine to pass around naked pointers to objects if you know your object lifetime semantics makes it safe.

In short; shared_ptr are good at what they do but they are not a catch all for all design problems (unique_ptr and others give difference usage semantics) nor do they remove the need for you, the programmer, to think about your design and object life times.

As for the 'fugly' arguement; C++ is hardly the most attractive of langauages however extended usage of things like this (more so when hidden behind typedefs) leads you to get use to it and removes that frankly dumb 'arguement'; I mean, hell, if you think shared_ptr<type> is ugly then you are going to hate the lambda syntax and avoiding that very powerful construct just because you think it looks 'fugly' makes you a fidiot

Share on other sites

I see this around a lot. I have to say, I choose to embrace the idea of keep using "delete" as I did in the last 20 years just to avoid having my code polluted with all that shared_ptr<Whatever> that makes C++ seriously fugly.

I think C++ needs a new keyword/operator for that, kind of what microsoft did using the "^" for .NET managed references in C++.

Syntactic sugar hides stuff under the carpet, it doesn't reduce complexity.

shared_ptr pollution is symptom of approach to solving problems.

bool GraphTraverser::traverse(shared_ptr<Node> node);[/quote]

My first question: why is traverse modifying the graph? Traverse should be something that doesn't mutate structure of the graph. Same as for_each concurrentModificationException, the invalidation of iterators or similar.

Reason that leads me to such guess is passing shared_ptr. Shared_ptr only does one thing - it manages lifecycle of objects. It should therefore be passed only into parts of code that modify lifecycle, such as allocate or free objects.

Consider slight redesign:bool GraphTraverser::traverse(Node & node);Now it's obvious one cannot change the structure anymore, we'll just visit and possibly affect contents.

While we're at it:std::for_each(graph.begin(), graph.end(), Visitor());Beautiful. No need to think what this does, we're using STL's idioms. But what if I suddenly do need to modify such graph? Well - std::erase(....).

Distaste for certain features and libraries of C++ comes from cross-polination of, most commonly Java, and to lesser degree C# concepts. Idiomatic up-to-date C++ code is fairly shallow and straight-forward (excluding template meta programming).

One of biggest pieces of missing knowledge is effective mapping of problems to STL interfaces and use of <algorithm>, which cover a lot of ground.

Of course it doesn't help that many crucial libraries are in C (good ones are well designed to fit nicely) or even worse, some fairly nondescript mixture of various languages. I consider Qt to be absolute disaster, might as well call it #include <java.hpp>.

Share on other sites

In particular, if you use exceptions.

nah.. exceptions are for pussies.. I just crash :asd:

@phantom
Actually I jumped on the lambda and auto bandwagon straight away. They are not as elegant as C#'s equivalents but they are not that bad.

@Antheus
As usual, great post... and you're right, your code is indeed beautiful and very "C++like". The example was just something on the top of my head, I don't even use a graph traverser anymore. I do think graphs are one of the things that shared_ptr dont do well, any solution I tried doesn't even come close to C#'s GC one as far as clarity and elegance. I don't know how to build a graph that is possible to iterate over with the std:for_each I'll have a look at that, but still, somewhere in Visitor you will have a shared_ptr<Node> passed in right?

I still think that syntactic sugar can make the difference between readable and unreadable code, shared_ptr<bla> has a VERY high noise to signal ratio.