How to make istringstream more efficient? [duplicate] - c++

This question already has answers here:
Creating an input stream from constant memory
(2 answers)
Closed 6 years ago.
#include <sstream>
using namespace std;
const char* GetHugeString();
int main()
{
const char* p = GetHugeString();
//
// Below will copy the huge string into a std::string object!
//
istringstream sstrm{p};
return {};
}
istringstream doesn't need a copy of the huge string; a null-terminated string pointer is enough. But istringstream's ctor only take std::string, rather than std::string_view(c++1z only), as its argument.
Is there a work-around to make std::istringstream more efficient in such a case?

You can simply assign the buffer used internally in the istringstream:
istringstream stream;
stream.rdbuf()->pubsetbuf(p, strlen(p));
This does not copy the string. Do note that pubsetbuf() wants char* not const char*, but it doesn't actually modify the string, so you might const_cast your C string pointer before passing it.

Related

How to convert an std::string_view to std::string? [duplicate]

This question already has answers here:
How to correctly create std::string from a std::string_view?
(3 answers)
Closed 1 year ago.
An std::string_view is kind of a replacement for char* in C. It's a string that is not copied from place to place, just as char* is just a place in memory that is referenced from time to time.
However, sometimes we need to transform it in a string for functions that accept a string.
How do I do that?
std::string has constructors that will accept a std::string_view as input, eg:
std::string_view sv{...};
std::string s1{sv};
std::string s2{sv, index, length};
Alternatively, you can use the std::string constructor that accepts a char* and length as input, eg:
std::string_view sv{...};
std::string s1{sv.data(), sv.size()};
std::string s2{sv.data()+index, length};
A std::string as a constructor for that, but only an explicit one.
void f(std::string s);
std::string_view sv;
f(sv); // Error! Cannot convert implicitly
f(std::string{sv}); // Works fine.
This has been designed like this to prevent accidental memory allocations.
See documentation for std::basic_string::basic_string (10)
Just use std::string's constructor:
std::string{my_string_view}

Why cant I use std::copy with std::string to another std::string? [duplicate]

This question already has answers here:
C++, copy set to vector
(8 answers)
How to copy std::string into std::vector<char>? [duplicate]
(2 answers)
Closed 2 years ago.
The following code prints an empty string and i am unable to understand why it is so?
#include <string>
#include <algorithm>
#include <iostream>
int main()
{
std::string s="hello";
std::string r;
std::copy(s.rbegin(),s.rend(), r.begin());
std::cout<<r;
return 0;
}
The problem is r is an empty std::string, it contains no chars. std::copy is trying to copy-assign chars since r.begin(), which leads to UB.
You can make r containing 5 elements in advance.
std::string r(5, '\0');
Or
std::string r;
r.resize(5);
Or use std::back_inserter.
std::string r;
std::copy(s.rbegin(),s.rend(), std::back_inserter(r));

string.c_str() is const? [duplicate]

This question already has answers here:
Can I get a non-const C string back from a C++ string?
(14 answers)
Closed 5 years ago.
I have a function in a library that takes in a char* and modifies the data.
I tried to give it the c_str() but c++ docs say it returns a const char*.
What can I do other than newing a char array and copying it into that?
You can use &str[0] or &*str.begin() as long as:
you preallocate explicitly all the space needed for the function with resize();
the function does not try to exceed the preallocated buffer size (you should pass str.size() as the argument for the buffer size);
when the function returns, you explicitly trim the string at the first \0 character you find, otherwise str.size() will return the "preallocated size" instead of the "logical" string size.
Notice: this is guaranteed to work in C++11 (where strings are guaranteed to be contiguous), but not in previous revisions of the standard; still, no implementation of the standard library that I know of ever did implement std::basic_string with noncontiguous storage.
Still, if you want to go safe, use std::vector<char> (guaranteed to be contiguous since C++03); initialize with whatever you want (you can copy its data from a string using the constructor that takes two iterators, adding a null character in the end), resize it as you would do with std::string and copy it back to a string stopping at the first \0 character.
Nothing.
Because std::string manages itself its contents, you can't have write access to the string's underlying data. That's undefined behavior.
However, creating and copying a char array is not hard:
std::string original("text");
std::vector<char> char_array(original.begin(), original.end());
char_array.push_back(0);
some_function(&char_array[0]);
If you know that the function will not modify beyond str.size() you can obtain a pointer in one of different ways:
void f( char* p, size_t s ); // update s characters in p
int main() {
std::string s=...;
f( &s[0], s.size() );
f( &s.front(), s.size() );
}
Note, this is guaranteed in C++11, but not in previous versions of the standard where it allowed for rope implementations (i.e. non-contiguous memory)
If your implementation will not try to increase the length of the string then:
C++11:
std::string data = "This is my string.";
func(&*data.begin());
C++03:
std::string data = "This is my string.";
std::vector<char> arr(data.begin(), data.end());
func(&arr[0]);
Here's a class that will generate a temporary buffer and automatically copy it to the string when it's destroyed.
class StringBuffer
{
public:
StringBuffer(std::string & str) : m_str(str)
{
m_buffer.push_back(0);
}
~StringBuffer()
{
m_str = &m_buffer[0];
}
char * Size(int maxlength)
{
m_buffer.resize(maxlength + 1, 0);
return &m_buffer[0];
}
private:
std::string & m_str;
std::vector<char> m_buffer;
};
And here's how you would use it:
// this is from a crusty old API that can't be changed
void GetString(char * str, int maxlength);
std::string mystring;
GetString(StringBuffer(mystring).Size(MAXLEN), MAXLEN);
If you think you've seen this code before, it's because I copied it from a question I wrote: Guaranteed lifetime of temporary in C++?

How to pass a dymamic array of strings pointers from C++ to a C function [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
std::vector<std::string> to char* array
I have to call a c function that accepts an array of string pointers. Example
void cFunction(char* cities[], int count)
{
for(int i = 0; i < count; ++i )
{
printf("%s\n", cities[i]);
}
}
Assume that function is in some third party libabry; it cannot be changed
I can declare a static array and call the function like this
char* placesA[] = {"Teakettle Junction", "Assawoman Bay", "Land O' Lakes", "Ion", "Rabbit Hask" };
cFunction(placesA, 5);
That works. But my data is dynamic i.e. the size of the array changes many times at runtime
So I tried this
std::vector<std::string> placesB(placesA, placesA + 5);
cFunction(&placesB[0], 5); // this won't work because std::string != char*[]
Tried this
std::vector<char*> placesC;
cFunction(&placesC[0], 5);
I find placesC awkward to populate at the sametime avoid memory leaks I am looking for a solution that is both efficient ( as little string copying as possible and preferably uses STL and or Boost )
You can write a function that populates a vector<char*> from a vector<string> using .c_str() on each string.
There's going to be some awkwardness no matter how you slice it. If the C API truly requires modifiable arrays, then that's what you'll need to provide -- you'll have to copy your strings into. If it doesn't modify the strings, then you can use a std::vector of const char*, where the string data is still owned by the underlying std::string objects; you just have to be careful that the C API doesn't hold onto references to those strings and tries to access them after the strings have been modified or deallocated.
For example, here's one way to do it:
// Unary functor which calls c_str() on a std::string object
struct StdStringCStrFunctor
{
const char *operator() (const std::string& str) { return str.c_str(); }
};
...
std::vector<std::string> places;
... // populate places
// Convert to array of C strings
std::vector<const char *> placesCStr(places.size());
std::transform(places.begin(), places.end(), placesCStr.begin(), StdStringCStrFunctor());
cFunction(const_cast<char**>(&placesCStr[0]), placesCStr.size());

How to convert std::string to const char*? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Convert std::string to const char* or char*
void Foo::bar(const std::string& foobar) {
// ...
const char* foobar2 = (char*)foobar;
// ...
}
That does not work and I get an error during compilation about invalid casting.
Is there some other way to convert std::string to const char*?
Use foobar.c_str().
You might find this link useful: http://www.cppreference.com/wiki/string/start
std::string::c_str() gets you a const char* pointer to a character array that represents the string (null-terminated).
You should not manipulate the data this pointer points to, so if you need to do that, copy the data.
Double edit - doing it in a more C++ fashion
Since it is nicer to avoid the use of raw pointers and arrays where possible, you can also get the data into an std::vector<char>
#include <string>
#include <vector>
int main()
{
std::string str = "Hello";
std::vector<char> cvec(str.begin(), str.end());
// do stuff
}
edit this is more like C since it uses raw pointers and explicitly allocates mem
#include <string>
#include <cstring>
int main()
{
std::string str = "Hello";
char *cptr = new char[str.size()+1]; // +1 to account for \0 byte
std::strncpy(cptr, str.c_str(), str.size());
// do stuff...
delete [] cptr;
}
You're going to get a lot of kinda incorrect answers about str.c_str() here. :) While c_str() is indeed useful, please keep in mind that this will not actually convert the string into a char*, but rather return the contents of the string as a const char*. And this is a big difference!
What's important here is that the pointer you obtain from c_str() is valid only as long as the given string object exists. So this would be terribly wrong:
class Something {
const char* name;
public:
Something(const std::string& pname) {
this->name = pname.c_str(); /* wrong! the pointer will go wrong as the object from the parameter ceases to exist */
}
};
So if you want to convert, as in: create a new value which will be independent of the original std::string, then you'll want to do something like this:
char* convert(const std::string& str) {
char* result = new char[str.length()+1];
strcpy(result,str.c_str());
return result;
}
But still c_str() will be quite enough for you in most cases. Just try to think in terms of objects' time of life.
const char* foobar2 = foobar.c_str();
Notice the const.
Otherwise you have to copy it to a char buffer.