🔒 Locked
String formatting in C++
Advertisement
Original Post
You can use a stringstream, which lets you fill a stream with iostream semantics.
Alternately, you can sprintf directly on STL strings:
[soruce]
string s (4096, ''\0''); // create buffer, null-filled
sprintf (&s[0], "Format String %d\n", arg);
[/source]
This is slightly less efficient than operating directly on a buffer since the string has to be initialized to a value before you write on it, but this code will work.
Alternately, you can sprintf directly on STL strings:
[soruce]
string s (4096, ''\0''); // create buffer, null-filled
sprintf (&s[0], "Format String %d\n", arg);
[/source]
This is slightly less efficient than operating directly on a buffer since the string has to be initialized to a value before you write on it, but this code will work.
quote:
Original post by Stoffel
This is slightly less efficient than operating directly on a buffer since the string has to be initialized to a value before you write on it...
Construct the string and then use reserve() instead of filling it with dummy values:
#include <string>
using std::string
int main()
{
string s;
s.reserve(4098);
sprintf (&s[0], "Format String %d\n", arg);
}
quote:
Original post by Stoffel
...but this code will work.
It "may" work. std::string''s representation (how it stores data) is not guaranteed to use a large C-style character array. I would recommend using stringstream''s formatting or simply format your own output into a stringstream. Avoid the C-style string operations where possible.
Not to start sparring or anything, ''cause I really admire null_pointers responses in general. However:
Even with that code, the string will not behave properly after the sprintf. You''ll have to resize the string to the length you''ve written. Otherwise, the next operation on the string (like s += string ("something new")) will assume s has zero length because you haven''t told it any different. You''d have to reserve, then resize to the new length of the string. I''m not entirely sure, but it may re-zero the memory on the resize after this call. I actually can''t even remember if string has a resize function at this time (on the GF''s computer, and I''ll be damned if I''m going to surf MSDN on dial-up).
Even if this method worked, it is still less efficient than using a stack buffer. std::string dynamically allocates memory whereas a stack buffer is allocated with the rest of the stack-local variables at the beginning of the function call.
It will work. string and vector both guarantee contiguous memory. In fact, they''re the only containers that do make this guarantee.
quote:
Construct the string and then use reserve() instead of filling it with dummy values:
Even with that code, the string will not behave properly after the sprintf. You''ll have to resize the string to the length you''ve written. Otherwise, the next operation on the string (like s += string ("something new")) will assume s has zero length because you haven''t told it any different. You''d have to reserve, then resize to the new length of the string. I''m not entirely sure, but it may re-zero the memory on the resize after this call. I actually can''t even remember if string has a resize function at this time (on the GF''s computer, and I''ll be damned if I''m going to surf MSDN on dial-up).
Even if this method worked, it is still less efficient than using a stack buffer. std::string dynamically allocates memory whereas a stack buffer is allocated with the rest of the stack-local variables at the beginning of the function call.
quote:
It "may" work. std::string''s representation (how it stores data) is not guaranteed to use a large C-style character array.
It will work. string and vector both guarantee contiguous memory. In fact, they''re the only containers that do make this guarantee.
Never use strstream!
Use stringstream instead (using the "sstream" header). With strstream, you must deal with buffers explicitely instead of using std::string. I'm not sure, but I think you must delete the buffer yourself in some cases... (and, as you wrote, you must explicitely add a null caracter)
alexk7@alexk7.com
Edited by - alexk7 on December 26, 2001 2:24:26 AM
Use stringstream instead (using the "sstream" header). With strstream, you must deal with buffers explicitely instead of using std::string. I'm not sure, but I think you must delete the buffer yourself in some cases... (and, as you wrote, you must explicitely add a null caracter)
|
alexk7@alexk7.com
Edited by - alexk7 on December 26, 2001 2:24:26 AM
quote:
Original post by Stoffel
Even with that code, the string will not behave properly after the sprintf. You''ll have to resize the string to the length you''ve written. Otherwise, the next operation on the string (like s += string ("something new")) will assume s has zero length...
Good point!
quote:
Original post by Stoffel
...You''d have to reserve, then resize to the new length of the string. I''m not entirely sure, but it may re-zero the memory on the resize after this call. I actually can''t even remember if string has a resize function at this time (on the GF''s computer, and I''ll be damned if I''m going to surf MSDN on dial-up).
Just replace the call to reserve(n) with a call to resize(n), and append the null-terminator where it is needed. Why call both reserve and resize? AFAIK, reserve is only useful to cut down on the memory reallocations and iterator invalidations needed when doing large numbers of push_back calls.
quote:
Original post by Stoffel
Even if this method worked, it is still less efficient than using a stack buffer. std::string dynamically allocates memory whereas a stack buffer is allocated with the rest of the stack-local variables at the beginning of the function call.
Probably. If speed is critical, create a char buffer and perform the C-style operations on it. In most circumstances, I should think that std::string with its support for different character types and locales would prove more useful. Hence the phrase "where possible" in my first post.
quote:
Original post by Stoffel
Dangit, you''re right. All that''s guaranteed is that string::c_str () will give you a C-portable null-terminated string.
Same goes for std::vector.
quote:
Same goes for std::vector
I don''t have an up-to-date C++ reference to hand, but I believe this to be incorrect.
I think that std::vector does guarantee being allocated in a contiguous block of memory (or at least, constant-time access to elements which can only be guaranteed through a contiguous block of memory).
quote:
Original post by DrPizza
I think that std::vector does guarantee being allocated in a contiguous block of memory (or at least, constant-time access to elements which can only be guaranteed through a contiguous block of memory).
That was my impression too, but I''ve already been wrong once this thread.
FWIW, "Effective STL" by Meyers, Item 16: "Know how to pass vector and string to legacy APIs"
"The elements in a vector are constrained by the C++ Standard to be stored in contiguous memory, jsut like an array."
The syntax is &v[0] (NOT v.begin ()), but you also have to check if the vector is empty yourself or the results are undefined.
quote:
Original post by Stoffel
"The elements in a vector are constrained by the C++ Standard to be stored in contiguous memory, jsut like an array."
The standard doesn't prescribe a particular representation for each standard container...For a vector, the element data structure is most likely an array. (Bjarne Stroustrop, "The C++ Programming Language", section 17.1.3, page 465), emphasis mine.
quote:
Original post by DrPizza
I think that std::vector does guarantee being allocated in a contiguous block of memory (or at least, constant-time access to elements which can only be guaranteed through a contiguous block of memory).
Constant-time access does not necessarily mean that elements within the representation will contiguous (i.e., a C-style array). Constant-time access relies on the assumption that the same set of calculations can find any element within the container, but it does not assume how far apart they are spaced (contiguity).
Example:
const int values_per_chunk = 32;
const int chunks_per_collection = 16;
struct chunk { int elements[values_per_chunk]; int other_data; };
struct collection { chunk chunks[chunks_per_collection]; };
int& access(collection& c, int n)
{
// demonstrates constant-time access without contiguity
const int chunk = n / values_per_chunk;
const int index = n - chunk * values_per_chunk;
return c.chunks[chunk].elements[subindex];
}
int main()
{
collection c; // 368 elements (0...367)
access(c, 233) = 5;
access(c, 128) = 2;
return 0;
}
Look up vector<bool> in "The C++ Programming Language" by Bjarne Stroustrop for a more useful example.
Edited by - null_pointer on December 28, 2001 12:48:36 PM
quote:
Original post by DrPizza
vector is an abomination
std::vector is a good, reasonably fast and efficient, general-purpose container. MSVC's standards compliance is an abomination.
quote:
Original post by DrPizza
...the standard still doesn't permit proxy classes to be returned from containers. Without them, it's not a container (because you can't reference each element individually).
What are you talking about?
Edited by - null_pointer on December 29, 2001 10:05:47 AM
i assume he''s talking about vector<bool>, the brackets probably got eaten by the board
vector<bool> is a vector specialization that actually uses a bitset to store the bools, and uses proxies to operate on them
you can read all about it here:
vector<bool> is nonconforming, and forces optimization choice (PDF)
vector<bool> is a vector specialization that actually uses a bitset to store the bools, and uses proxies to operate on them
you can read all about it here:
vector<bool> is nonconforming, and forces optimization choice (PDF)
Good points regarding vector<bool>.
kvh: I do not understand how vector<bool> could use a bitset for storage. vector<bool> is a variable-length bit "container," whereas bitset is a constant-length bit "container."
kvh: I do not understand how vector<bool> could use a bitset for storage. vector<bool> is a variable-length bit "container," whereas bitset is a constant-length bit "container."
As further proof of there being no guarantee that vector allocates a contiguous block, consider that it provides no function to retrieve a pointer to that block. That would be plenty useful if, say, calling a C function expecting a normal array. But there isn''t such a function, and I''m positive that it''s because the block might not be contiguous. Of course, we all know that a dynamically-allocated array is the most likely implementation; we also know that we must also never make assumptions.
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement