const char * or std::string?

Started by
27 comments, last by ToohrVyk 16 years, 1 month ago
I know most people will say you should always use std::string over const char *, but for things like filenames, would const char * be preferred? I'm thinking for cross-platform, especially consoles with limited memory, where creating std::strings would potentially create small allocations on the heap, just before files were loaded in, thus fragmenting memory.
Advertisement
Even on console, you still want to use things that make your life easier (and make coding simpler). As for fragmentation, you don't want one giant heap (that's always going to end badly), so you have multiple pools -- so allocations are sorted either by lifetime/function or by size. If you do that, then your temporary string allocations for things like filenames won't be in the same pool as file data anyways, so it doesn't really matter.
Don't make coding harder on yourself just because you *may* want to target some platform where std::string *may* become a problem. You should only worry about this level of optimization when you're sure it's a problem.

Anyways, I believe most std::string implementations actually keep a small char array around to avoid dynamic memory allocation for very small strings. So it may be a total non factor.
osmanb:
can you give pointers on using different heaps? (no pun intended)

suppose I have a code section which uses a few thousands new/delete pairs and I don't want to fragment the heap, how can I tell it to use an alternative heap?

temporarily overload the new/delete operators?
Quote:Original post by f8k8

where creating std::strings would potentially create small allocations on the heap, just before files were loaded in, thus fragmenting memory.


How long will these strings live?

If they are created and destroyed, it's unlikely they'll contribute much to fragmentation, especially if we're talking hundreds or thousands of such strings per application life-time.

Quote:but for things like filenames


Ok, so you're traversing the disk 10 times a second, allocating tens of thousands of filenames..... Why? And if not, how many allocations/de-allocations are you making per second?


My experience with files has been that whenever you try to manipulate the filenames (concat, for example), char strings are absolute nightmare.

Consider this - you have your path string, to which you need to append '/', then filename, then extension. How will you handle this?

You can obviously create target buffer on stack (char[8192]; // just to be safe). Next, you need to juggle with strcat and similar mess, relying on strlen. One invalid string, and everything enters the realm of undefined behavior. And in the end, you need to create a properly sized buffer on heap, and pass that on.

So, in the end, you are doing exactly the same thing std::string does, except that you need to do the same thing *for every string manipulation*. And since releasing memory this way is unreliable, you'll write a wrapper class. And presto - you re-invented std::string.

-----

Alternate answer - if you need to ask this question, you're not ready to deal with such low level approach. If you knew the actual allocation issues, you wouldn't need to ask this, you'd evaluate allocation patterns, then write a std::allocator for your strings, and use that.

Quote:especially consoles with limited memory


They'll be almost certainly using pre-allocated memory blocks, so the question how you access that becomes a moot point.

Quote:suppose I have a code section which uses a few thousands new/delete pairs and I don't want to fragment the heap, how can I tell it to use an alternative heap?


For std::containers, there's std::allocator. For other purposes, see how templated or type based allocators work.

First way to improve performance is not to allocate anything. Only when you're absolutely positively sure that you cannot do what you want on stack, use pre-allocated storage.

Why do you have thousands of heap allocations. I manage to get by with dozens per application.

See Placement new
Quote:Original post by Iftah
osmanb:
can you give pointers on using different heaps? (no pun intended)

suppose I have a code section which uses a few thousands new/delete pairs and I don't want to fragment the heap, how can I tell it to use an alternative heap?

temporarily overload the new/delete operators?


For the C++ standard library, std::basic_string, has three template arguments. You can use the third to specify an allocator. For example, you can use typedef std::basic_string<char, std::char_traits<char>, boost::pool_allocator<char> > MyPoolAllocatedString.
I'd say this doesn't worth the extra effort. You can use strings with a custom allocator such as boost::pool_allocator and boost::fast_pool_allocator.
Depends entirely on your needs.

If you need primarily temporary strings, you could make a simple TString<MAX_PATH> class which created a string with an std::string style interface. With a template parameter specifying the internal array size, you wouldn't need to worry about stack allocations. An std::string link interface would make it easy to change between implementations.

The two extremes -

You could try to do away with strings entirely and switch over to an ID based approach (if you plan on having a huge number of identifiers, etc), no dynamic content, etc.

You could just go with std::strings and procrastinate on the issue until you hit problems.

Both are totally viable and depend on the needs of your project and what tradeoffs you need to make.
Just use std::string, there's no reason not to, and if at a later date you do find that the string allocations are causing you problems (not that you're likely to) then just plug in a smarter allocator.
Writing your own string class, or manually managing char* arrays is going to cause you more headaches in both the short and long term; not to mention the probable loss in efficiency of doing it yourself.
On top of that, most std::string implementations have a small buffer (12-16 characters) as a fixed array in the class. That means that for short strings, no heap allocations will take place at all while a char * approach would not only harass you with memory management, but actually _reduce_ performance.

-Markus-
Professional C++ and .NET developer trying to break into indie game development.
Follow my progress: http://blog.nuclex-games.com/ or Twitter - Topics: Ogre3D, Blender, game architecture tips & code snippets.

This topic is closed to new replies.

Advertisement