4

I have a method / function:

void foo() {

  static const std::string strSQLQuery = "SELECT ... ";
  // or maybe
  const std::string strSQLQuery = "SELECT ... "; 

  // some operations on strSQLQuery
  // i.e. concatenating with WHERE, etc.:
  const std::string strSQL = strSQLQuery + strWHERE;

  doSthOnDataBase(strSQL);
}

(SQL is only an example)

  1. static const will be initialized only once, but persists in memory until the process ends.
  2. const will be initialized every time foo() is run, but the memory (stack) is freed when the {} block ends.

On the other hand, the string "SELECT ... " has to be still hardcoded in the program code. And it's no matter if we use 1. or 2.

So which approach is better? Using static const std::string or only const std::string?

Or maybe there's no one answere, because it depends how I want to use foo() -- call it 1000 times per second (then I don't want to initialize a variable every time) or call it 1000 times per month (then I don't care).

(I've read Question Difference between static const char* and const char* and especially answer https://stackoverflow.com/a/2931146/945183, but they apply to const char*.)

Community
  • 1
  • 1
jacek.ciach
  • 904
  • 11
  • 20
  • 7
    You seems to have already outlined the pros and the cons of each solution. Hint: There's no absolute better. – Shoe Jan 24 '14 at 10:20
  • Note that your program takes a lock when you have a `static` like this. – Simple Jan 24 '14 at 10:41
  • I would go for the static const because it requires less memory (stack is a very expensive thing to waste) and it basically has the same effect. As a side note, it's very uncommon to have a const define in a method you usually define it globally of as a member of a structure... – Pandrei Jan 24 '14 at 11:01
  • Q: Would constexpr help hint to the compiler that it should be optimized as a compile-time constant? Seems to me that const is enough. Also, if you're writing SQL, is this really your bottleneck? – leewz Jan 24 '14 at 11:27
  • 1
    @Pandrei: wat. A static string means your code will explode if used in a multithreaded context. A non-static thread means that a few bytes are put on the stack, and the rest on the heap. I have no clue what you are talking about wrt. "stack memory is expensive to waste". – jalf Jan 24 '14 at 11:37
  • @leewangzhong If I could use `constexpr`, it would help. But the compiler (it's not up to me) uses C++98. – jacek.ciach Jan 24 '14 at 11:38
  • If it's really about performance then you've neglected a third option: use a `static const` global string. – Steve Jessop Jan 24 '14 at 11:42
  • @jalf I recommend you read a bit more about multi - threaded environments and c++ in general; scott meyers - effective c++ is a nice read. Static const string are ok in a multi-threaded environment the key here is the const attribute- so you don't actually require any locks. – Pandrei Jan 24 '14 at 11:48
  • 1
    You may use `const char* const strSQLQuery = "SELECT ... "`. – Jarod42 Jan 24 '14 at 12:55
  • @Jarod42 I know I can use `const char*`, but my question applies to local non-primitives. – jacek.ciach Jan 24 '14 at 13:07
  • @jacek.ciach: My remark is specific to `const string`, you avoid some unneeded memory allocation using directly `const char*`. Personally, I would use `const auto strSQLQuery = "SELECT ..."` (which is of type `const char*`). – Jarod42 Jan 24 '14 at 13:26
  • You don't care about threads? And the question is about a general user-defined object with a constructor, not just std::string? Use static: saves you cost of repeated construction and destruction. – leewz Jan 24 '14 at 13:31
  • @Jarod42, isn't it const char * const? – leewz Jan 24 '14 at 13:33
  • @leewangzhong: `auto` is `const char*` ;) which gives `const char* strSQLQuery const`. – Jarod42 Jan 24 '14 at 13:42
  • @leewangzhong I do care. And the Q. is about std::string. (I have corrected my last edit.) – jacek.ciach Jan 24 '14 at 14:13
  • @jacek.ciach And you're sure this isn't a case of premature optimization? I'm not clear on why you'd WANT to use `const std::string` instead of `const char[]`, which would definitely avoid unnecessary dynamic allocations, nor what you're doing with these strings that would mean the savings matter (the cost of working in memory is usually waaaay less than I/O). – leewz Jan 25 '14 at 02:52
  • @leewangzhong No, no, no... I'm sure it's not the case. I am not wondering what is better, namely, faster. I just wanted to know maybe other prons and cons besides those I've mentioned. And I've learnt: I have to take threads into account. – jacek.ciach Jan 25 '14 at 15:57
  • @leewangzhong Why I WANT `const std::string` instead of `const char[]`? It's because the example I provided is much more simpler then the real code I meet in the company; and the code uses not `std::string`, but its own equivalent of `std::string`. Unfortunately the equivalent doesn't ,,like'' `const char*`... – jacek.ciach Jan 25 '14 at 16:03

4 Answers4

2

Profile it. Chances are, the trip to the database so utterly dwarfs the initialization cost of the strings that it doesn't matter.

And as has been pointed out, local statics are not thread-safe on all compilers. They are in GCC, and C++11 requires them to be, but it took Microsoft until VS2013 to actually implement this.

Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
  • It took MS until VS2013 to properly implement some of C++11. They're still not quite there yet... – rubenvb Jan 24 '14 at 14:41
  • I know, that the weTeim's answer is similar to this one, but Sebastian ,,went to the point'' better, IMHO, and did not repeat thoughts I included in my Question. – jacek.ciach Jan 25 '14 at 15:54
1

Well if a member variable, static const is safe so long as you don't intentionally defeat the const part by casting. But from your linked comments a local variable is different:

A local static variable is initialized the first time its definition is encountered, but not destructed when the function exits. So it keeps its value between invocations of the function.

To make this safe, gcc emits locking to protect the initialization but MS C++ does not as described here, so this can be either safe or not depending on the compiler and even if supposedly safe can have inimical side effects.

The tradeoff here seems to be efficiency versus maintainability. Is that extra little speed worth the possibility of introducing some subtle error. While researching this, I've come full circle on my opinion now, I'd say usually no. Especially since in this case it's a simple string initialization followed up by a lengthly database call.

Community
  • 1
  • 1
waTeim
  • 9,095
  • 2
  • 37
  • 40
0

As I known "static" is not necessary in your case. 1) When you declare and define a const variable, compiler has a chance to replace all occurrences with the value you assigned, like following:

const int var = 9;
int b = sqrt( var );

will become

int b = sqrt( 9 );

This behaves just like #define in C style. If this is what you want, then you already have it without "static".

2) As others told, static variables will remain existence even after foo() returns. I suppose this is not your objective

faraday
  • 41
  • 3
  • 1
    `std::string` is dynamically initialized and user-defined. Good luck finding a compiler doing constant propagation on that. – Sebastian Redl Jan 24 '14 at 11:36
0

Static non-primitive locals (const or not) do atomic read on every function call (initialization flag). They are thread safe (speaking of GCC) only when requested specifically via a compiler flag. The string strSQL constructed at run-time will be much more of a performance hit (because of heap allocation) than static initialization caused atomic read.

The fastest would be something like this:

void call(std::string const& where) {
    static char prefix[] = "SELECT ...";

    std::string strSQL;
    strSQL.reserve(sizeof(prefix)/sizeof(char) + strWHERE.size()); 
    strSQL.append(prefix, sizeof(prefix)/sizeof(char)).append(strWHERE);
    ...
}

Whether you need to sacrifice readability for speed is another question.

bobah
  • 18,364
  • 2
  • 37
  • 70