C++ questions

Discussion of chess software programming and technical issues.

Moderator: Ras

lucasart
Posts: 3243
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: C++ stringstream

Post by lucasart »

mar wrote:Shouldn't that be it->second = value instead?
Thank you! Actually

Code: Select all

it->second.value = value;
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.
lucasart
Posts: 3243
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: C++ stringstream

Post by lucasart »

Sven Schüle wrote:
lucasart wrote:I typically have to change engine options at runtime
I'd assume that typically you only change option values at runtime while the set of supported options itself stays constant. Your "struct Option" data structure combines a static, descriptive part specifying what your program supports, and a dynamic part containing a value per option, initially set to some default.

Sven
Exactly:

Code: Select all

struct Option
{
	enum Type { Boolean, Integer };
	Type type;
	std::string name;
	int value, min, max;

	typedef std::pair<Type, std::string> Key;
};
However it's a little trickier, because:
* the static part is actually (type, name, min, max)
* the key (defining uniqueness) is (type, name) only. it is not acceptable to have two options with the same (type, name) that differ from their (min, max).
* the dynamic part is only the value. the (min, max) are static.

I suppose I could break the Option struct in two:

Code: Select all

struct Option
{
	enum Type { Boolean, Integer };
	Type type;
	std::string name;
	int min, max;
	typedef std::pair<Type, std::string> Key;
};

struct OptionValue {
	int value;
};
For now OptionValue looks like a do-nothing wrapper, but later on, I will add std::string as a possible OptionValue. So we need this flexibility.

Thanks for the suggestion. It does make a lot of sense to do it that way.
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.
lucasart
Posts: 3243
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: C++ stringstream

Post by lucasart »

Another noob question on C++. I can't figure out how to use std::string. Here's is the code that I'm trying to do:

Code: Select all

std::string s;
int time = 60000, inc = 1000;
s += "go wtime " + time + " winc " + inc;
I can do this with a stringstream, but it's so convoluted and ugly. Then I'd have to "paste" my stringstream into the original string.
Ideally I want to use a function like printf() where I can define a format:

Code: Select all

...("go wtime %d winc %d", wtime, winc)
How does one do that in C++ ?
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.
lucasart
Posts: 3243
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: C++ stringstream

Post by lucasart »

lucasart wrote:Another noob question on C++. I can't figure out how to use std::string. Here's is the code that I'm trying to do:

Code: Select all

std::string s;
int time = 60000, inc = 1000;
s += "go wtime " + time + " winc " + inc;
I can do this with a stringstream, but it's so convoluted and ugly. Then I'd have to "paste" my stringstream into the original string.
Ideally I want to use a function like printf() where I can define a format:

Code: Select all

...("go wtime %d winc %d", wtime, winc)
How does one do that in C++ ?
OK I managed to get the stringstream version working:

Code: Select all

std::ostringstream ostrm;
int time = 60000, inc = 1000;
ostrm << "go wtime " << time << " winc " << inc;
std::string s = ostrm.str();
But I'm a little worried about the performance of such a code. If I understand correctly:
* ostrm is created and initialized with an empty string (and possibly some prealloc of some size I don't know)
* every single << is really a function call, which would do two things: (1) handle the resizing of the string (2) some kind of strcat()
* a new string s is created (allocation and initialization) and it's "buffer" is copied from the one of ostrm. The allocation is optimized because it knows how many bytes to allocate.
* the temporary ostrm still lives (with memory allocated on free store), and will die when gets out of scope and gets destructed.

Isn't there a more efficient way of doing this ?

I'm just worried that all this C++ syntactic sugar can make some code "look nice" (though a sprintf() is far more straightforward and more readable) but actually hide some terrible inefficience if one doesn't know what is behind it (ie. how string and ostrm are implemented and exactly what all these operators do).
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.
mar
Posts: 2673
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: C++ stringstream

Post by mar »

I'm not sure (never used std::string/streams) but I bet it does the same as std::vector, i.e. it grows capacity 2x when needed and subsequent additions should be fast (i.e. no reallocation) until it needs more space again.
If you are used to sprintf then I see no problem doing sprintf to a buffer then assign it to a string, but maybe that would be considered ugly by some.
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: C++ stringstream

Post by Sven »

lucasart wrote:OK I managed to get the stringstream version working:

Code: Select all

std::ostringstream ostrm;
int time = 60000, inc = 1000;
ostrm << "go wtime " << time << " winc " << inc;
std::string s = ostrm.str();
But I'm a little worried about the performance of such a code. If I understand correctly:
* ostrm is created and initialized with an empty string (and possibly some prealloc of some size I don't know)
* every single << is really a function call, which would do two things: (1) handle the resizing of the string (2) some kind of strcat()
* a new string s is created (allocation and initialization) and it's "buffer" is copied from the one of ostrm. The allocation is optimized because it knows how many bytes to allocate.
* the temporary ostrm still lives (with memory allocated on free store), and will die when gets out of scope and gets destructed.

Isn't there a more efficient way of doing this ?

I'm just worried that all this C++ syntactic sugar can make some code "look nice" (though a sprintf() is far more straightforward and more readable) but actually hide some terrible inefficience if one doesn't know what is behind it (ie. how string and ostrm are implemented and exactly what all these operators do).
Don't worry, std::string and streams are quite fast, and definitely fast enough for your application of a tournament CLI. Things like I/O, network communication, or inter-process communcation typically take much more time than some string or stream operations. Building large tables of data will require attention, but fiddling with some strings should not cause any performance trouble for your application.

As to your remark about sprintf() vs. streams: I agree that the good old sprintf() looks much more straightforward, and personally I still tend to like sprintf() more than streams. But it also depends on the type of program you write. In a complex program with lots of different data types where writing type-safe code is really an issue it makes sense to use the "advanced", "pure" C++ way based on streams. For small programs sprintf() may be sufficient even though it also has functional disadvantages: sprintf() requires the buffer to already have the appropriate size when it is called, possibly including a calculation of maximum allowed string lengths for "%s" arguments etc., while streaming allows dynamic resizing within the implementation of "operator<<". Some security issues are related to that point.

Sven
lucasart
Posts: 3243
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: C++ stringstream

Post by lucasart »

mar wrote: I'm not sure (never used std::string/streams) but I bet it does the same as std::vector, i.e. it grows capacity 2x when needed and subsequent additions should be fast (i.e. no reallocation) until it needs more space again.
ok, thank you.
mar wrote: If you are used to sprintf then I see no problem doing sprintf to a buffer then assign it to a string, but maybe that would be considered ugly by some.
sprintf() is really doing things the C-way, and I want to learn the C++-way, so I force myself not to hack around C++ with C code (otherwise I'll never learn).

I would say there are pros and cons of doing an sprintf() here:

1/ pros

Code: Select all

char s[0x100];
sprintf(s, "go wtime %d wind %d", time, inc);
- is far more concise and readable than a spaghetti code with a bunch of <<
- the allocation is uber-fast: it is allocated on the stack by moving the stack pointer (a single assembly op code)

2/ cons

- 0x100 is a magic number that comes out of nowhere
- 0x100 is assumed by the programmer to be large enough to avoid overflow (risky if you screw up, and painful to debug some segfaulty code afterwards)
- if you make the number too large to be on the safe side every time, you'll end up wasting a lot of memory, and more importantly stack memory, which you can easily run out of (perhaps not on a modern PC, but on mobile devices or whatever)

=> Anyway, it's good to have both at your disposal, so you can make the correct decision when a trade-off needs to be made. I'll try to do things the C++ way first, and only when I have some performance issue, and after profiling the code, I might do some low-level optimization.
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.
lucasart
Posts: 3243
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: C++ stringstream

Post by lucasart »

But I'm a bit disappointed about C++ here. The whole STL thing is about allowing programmers to write high-level code, right ? So why didn't the C++ standard define operators that allow people to simply write:

Code: Select all

int time = 60000, inc = 1000;
string s = "go wtime " + time + " inc " + inc;
I think this would be even more efficient than going through a stringstream. There would be no need to allocate a second string (the one contained by the stringstream). And the code would be much more natural and familiar to people with a background in true high-level languages, where a string is a native type.

Is there any reason why they didn't want to, or couldn't do it ?
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.
mar
Posts: 2673
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: C++ stringstream

Post by mar »

lucasart wrote:But I'm a bit disappointed about C++ here. The whole STL thing is about allowing programmers to write high-level code, right ? So why didn't the C++ standard define operators that allow people to simply write:

Code: Select all

int time = 60000, inc = 1000;
string s = "go wtime " + time + " inc " + inc;
I think this would be even more efficient than going through a stringstream. There would be no need to allocate a second string (the one contained by the stringstream). And the code would be much more natural and familiar to people with a background in true high-level languages, where a string is a native type.

Is there any reason why they didn't want to, or couldn't do it ?
The reason is simply that the operator + is defined for std::string, not string literal. So if you wrote string("go wtime") + ..., it should work fine.
mar
Posts: 2673
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: C++ stringstream

Post by mar »

lucasart wrote: sprintf() is really doing things the C-way, and I want to learn the C++-way, so I force myself not to hack around C++ with C code (otherwise I'll never learn).
Well the problem is that STL is only optional, for convenience, so I would learn the language itself first, then libraries. STL isn't bad but IMHO it could have been much better, hard to say. The reason I stick with STL is that it's well tested (therefore there should be no surprises like bugs) and that some debuggers support it natively, i.e. you see containers in human-readable form, which is of course convenient. STL also demonstrates the power of the language, namely templates.
I would say there are pros and cons of doing an sprintf() here:

1/ pros

Code: Select all

char s[0x100];
sprintf(s, "go wtime %d wind %d", time, inc);
- is far more concise and readable than a spaghetti code with a bunch of <<
- the allocation is uber-fast: it is allocated on the stack by moving the stack pointer (a single assembly op code)

2/ cons

- 0x100 is a magic number that comes out of nowhere
- 0x100 is assumed by the programmer to be large enough to avoid overflow (risky if you screw up, and painful to debug some segfaulty code afterwards)
- if you make the number too large to be on the safe side every time, you'll end up wasting a lot of memory, and more importantly stack memory, which you can easily run out of (perhaps not on a modern PC, but on mobile devices or whatever)

=> Anyway, it's good to have both at your disposal, so you can make the correct decision when a trade-off needs to be made. I'll try to do things the C++ way first, and only when I have some performance issue, and after profiling the code, I might do some low-level optimization.
I absolutely agree. A very thorough reasoning.
Now imagine std::string had a method named format(). That would be nice :) Unfortunately it has not. One of the many reasons I wrote my own String class (note that I'm not recommending you to do the same, just stating my opinion).