My programmer has lots of memcpy. I want to avoid them.
I want to get a struct like boost::string_ref.
I want to know.
uint32_t len = 20;
char *p = new char[len];
memset(p, 0x00, len)
memcpy(p, "aaaa", 4);
string str(p, 4);// whether is use memcpy or not ?
const string str2(p, 4); //whether is use memcpy or not
//if it used memcpy, how to avoid memcpy ?
string_ref->string
string_view->string
string->string_ref
string->string_view
char* ->string
string->string
please tell me how to judge whether function used memcpy ?
Use an std::string_view to avoid copying the string.
#include <string_view>
// ...
const string_view strview(p, 4);
Keep in mind that string views are not guaranteed to be null-terminated, so be careful when using them in APIs that expect a null-terminated char*. Also, when the string they are viewing goes out of scope, the string view itself becomes invalid (just like a pointer would.)
I've been wondering about the following issue: assume I have a C style function that reads raw data into a buffer
int recv_n(int handle, void* buf, size_t len);
Can I read the data directly into an std:string or stringstream without allocating any temporal buffers? For example,
std::string s(100, '\0');
recv_n(handle, s.data(), 100);
I guess this solution has an undefined outcome, because, afaik, string::c_str and string::data might return a temporal location and not necessarily return the pointer to the real place in the memory, used by the object to store the data.
Any ideas?
Why not use a vector<char> instead of a string? That way you can do:
vector<char> v(100, '\0');
recv_n(handle, &v[0], 100);
This seems more idiomatic to me, especially since you aren't using it as a string (you say it's raw data).
Yes, after C++11.
But you cant use s.data() as it returns a char const*
Try:
std::string s(100, '\0');
recv_n(handle, &s[0], 100);
Depending on situation, I may have chosen a std::vector<char> especially for raw data (though it would all depend on usage of the data in your application).
In a recent question, I learned that there are situations where you just gotta pass a char* instead of a std::string. I really like string, and for situations where I just need to pass an immutable string, it works fine to use .c_str(). The way I see it, it's a good idea to take advantage of the string class for its ease of manipulation. However, for functions that require an input, I end up doing something like this:
std::string str;
char* cstr = new char[500]; // I figure dynamic allocation is a good idea just
getstr(cstr); // in case I want the user to input the limit or
str = cstr; // something. Not sure if it matters.
delete[] cstr;
printw(str.c_str());
Obviously, this isn't so, uh, straightforward. Now, I'm pretty new to C++ so I can't really see the forest for the trees. In a situation like this, where every input is going to have to get converted to a C string and back to take advantage of string's helpful methods, is it just a better idea to man up and get used to C-style string manipulation? Is this kind of constant back-and-forth conversion too stupid to deal with?
In the example you give, you can generally read a line into a std::string using the std::getline function: http://www.cplusplus.com/reference/string/getline/
Of course this doesn't do everything that a curses library does. If you need a non-const char* so that some C function can read into it, you can use a vector<char>. You can create a vector<char> from a string, and vice-versa:
std::string a("hello, world");
std::vector<char> b(a.begin(), a.end());
// if we want a string consisting of every byte in the vector
std::string c(b.begin(), b.end());
// if we want a string only up to a NUL terminator in the vector
b.push_back(0);
std::string d(&b[0]);
So your example becomes:
std::vector<char> cstr(500);
getnstr(&cstr[0], 500);
printw(&cstr[0]);
Most std::string::c_str() implementations (if not all of them) simply return a pointer to an internal buffer. No overhead whatsoever.
Beware however that c_str() returns a const char*, not a char*. And that the pointer will become invalid after the function call. So you cannot use it if the function does anything like writing back into the passed string or makes a copy of the pointer.
I want to convert a C-style string into a byte-vector.
A working solution would be converting each character manually and pushing it on the vector. However, I'm not satisfied with this solution and want to find a more elegant way.
One of my attempts was the following:
std::vector<byte> myVector;
&myVector[0] = (byte)"MyString";
which bugs and gets me an
error C2106: '=': left operand must be l-value
What is the correct way to do this?
The most basic thing would be something like:
const char *cstr = "bla"
std::vector<char> vec(cstr, cstr + strlen(cstr));
Of course, don't calculate the length if you know it.
The more common solution is to use the std::string class:
const char *cstr;
std::string str = cstr;
STL containers such as vector always take ownership, i.e. they manage their own memory. You cannot modify the memory managed internally by an STL container. For that reason, your attempt (and any similar attempt) is doomed to failure.
The only valid solution is to copy the memory or to write a new STL-style container that doesn’t take ownership of the memory it accesses.
Something along these lines should work
std::vector<byte> myVector = std::vector((byte*)cstring, (byte*)ctring + strlen(cstring))
Also, this is still going to just iterate through the c string and insert the values into the vector. Like Konrad said, that's just how you have to do it since vectors manage their own memory.
In case you would not like to copy the original string and would just like to iterate over it as an array of bytes, then C++20 has std::span to offer.
auto const const_bytes = std::as_bytes(std::span{str.data(), str.size()});
std::span<const std::byte> provides std::vector like iterating capabilities which I think is what you might be looking for.
Note: The original string would have to remain valid for the entire scope of std::span variable
std::vector<byte> myVector;
const char* str = "MyString";
myVector.assign( str, str+strlen(str) );
The most obvious question would be why you don't just use std::string:
std::string myString("MyString");
but if you really think you need a vector:
char myString[] = "MyString";
std::vector<byte> myVector(myString, myString+sizeof(myString));
You might also want to consider using std::tr1::array:
std::tr1::array<byte, sizeof("MyString")> myArray = {"MyString"};
C++ 0x will also have std::array.
const char *cstr = "bla"
std::vector<char> vec;
vec.resize(strlen(cstr)+1);
strcpy(&vec[0],cstr);
Const-correctness in C++ is still giving me headaches. In working with some old C code, I find myself needing to assign turn a C++ string object into a C string and assign it to a variable. However, the variable is a char * and c_str() returns a const char []. Is there a good way to get around this without having to roll my own function to do it?
edit: I am also trying to avoid calling new. I will gladly trade slightly more complicated code for less memory leaks.
C++17 and newer:
foo(s.data(), s.size());
C++11, C++14:
foo(&s[0], s.size());
However this needs a note of caution: The result of &s[0]/s.data()/s.c_str() is only guaranteed to be valid until any member function is invoked that might change the string. So you should not store the result of these operations anywhere. The safest is to be done with them at the end of the full expression, as my examples do.
Pre C++-11 answer:
Since for to me inexplicable reasons nobody answered this the way I do now, and since other questions are now being closed pointing to this one, I'll add this here, even though coming a year too late will mean that it hangs at the very bottom of the pile...
With C++03, std::string isn't guaranteed to store its characters in a contiguous piece of memory, and the result of c_str() doesn't need to point to the string's internal buffer, so the only way guaranteed to work is this:
std::vector<char> buffer(s.begin(), s.end());
foo(&buffer[0], buffer.size());
s.assign(buffer.begin(), buffer.end());
This is no longer true in C++11.
There is an important distinction you need to make here: is the char* to which you wish to assign this "morally constant"? That is, is casting away const-ness just a technicality, and you really will still treat the string as a const? In that case, you can use a cast - either C-style or a C++-style const_cast. As long as you (and anyone else who ever maintains this code) have the discipline to treat that char* as a const char*, you'll be fine, but the compiler will no longer be watching your back, so if you ever treat it as a non-const you may be modifying a buffer that something else in your code relies upon.
If your char* is going to be treated as non-const, and you intend to modify what it points to, you must copy the returned string, not cast away its const-ness.
I guess there is always strcpy.
Or use char* strings in the parts of your C++ code that must interface with the old stuff.
Or refactor the existing code to compile with the C++ compiler and then to use std:string.
There's always const_cast...
std::string s("hello world");
char *p = const_cast<char *>(s.c_str());
Of course, that's basically subverting the type system, but sometimes it's necessary when integrating with older code.
If you can afford extra allocation, instead of a recommended strcpy I would consider using std::vector<char> like this:
// suppose you have your string:
std::string some_string("hello world");
// you can make a vector from it like this:
std::vector<char> some_buffer(some_string.begin(), some_string.end());
// suppose your C function is declared like this:
// some_c_function(char *buffer);
// you can just pass this vector to it like this:
some_c_function(&some_buffer[0]);
// if that function wants a buffer size as well,
// just give it some_buffer.size()
To me this is a bit more of a C++ way than strcpy. Take a look at Meyers' Effective STL Item 16 for a much nicer explanation than I could ever provide.
You can use the copy method:
len = myStr.copy(cStr, myStr.length());
cStr[len] = '\0';
Where myStr is your C++ string and cStr a char * with at least myStr.length()+1 size. Also, len is of type size_t and is needed, because copy doesn't null-terminate cStr.
Just use const_cast<char*>(str.data())
Do not feel bad or weird about it, it's perfectly good style to do this.
It's guaranteed to work in C++11. The fact that it's const qualified at all is arguably a mistake by the original standard before it; in C++03 it was possible to implement string as a discontinuous list of memory, but no one ever did it. There is not a compiler on earth that implements string as anything other than a contiguous block of memory, so feel free to treat it as such with complete confidence.
If you know that the std::string is not going to change, a C-style cast will work.
std::string s("hello");
char *p = (char *)s.c_str();
Of course, p is pointing to some buffer managed by the std::string. If the std::string goes out of scope or the buffer is changed (i.e., written to), p will probably be invalid.
The safest thing to do would be to copy the string if refactoring the code is out of the question.
std::string vString;
vString.resize(256); // allocate some space, up to you
char* vStringPtr(&vString.front());
// assign the value to the string (by using a function that copies the value).
// don't exceed vString.size() here!
// now make sure you erase the extra capacity after the first encountered \0.
vString.erase(std::find(vString.begin(), vString.end(), 0), vString.end());
// and here you have the C++ string with the proper value and bounds.
This is how you turn a C++ string to a C string. But make sure you know what you're doing, as it's really easy to step out of bounds using raw string functions. There are moments when this is necessary.
If c_str() is returning to you a copy of the string object internal buffer, you can just use const_cast<>.
However, if c_str() is giving you direct access tot he string object internal buffer, make an explicit copy, instead of removing the const.
Since c_str() gives you direct const access to the data structure, you probably shouldn't cast it. The simplest way to do it without having to preallocate a buffer is to just use strdup.
char* tmpptr;
tmpptr = strdup(myStringVar.c_str();
oldfunction(tmpptr);
free tmpptr;
It's quick, easy, and correct.
In CPP, if you want a char * from a string.c_str()
(to give it for example to a function that only takes a char *),
you can cast it to char * directly to lose the const from .c_str()
Example:
launchGame((char *) string.c_str());
C++17 adds a char* string::data() noexcept overload. So if your string object isn't const, the pointer returned by data() isn't either and you can use that.
Is it really that difficult to do yourself?
#include <string>
#include <cstring>
char *convert(std::string str)
{
size_t len = str.length();
char *buf = new char[len + 1];
memcpy(buf, str.data(), len);
buf[len] = '\0';
return buf;
}
char *convert(std::string str, char *buf, size_t len)
{
memcpy(buf, str.data(), len - 1);
buf[len - 1] = '\0';
return buf;
}
// A crazy template solution to avoid passing in the array length
// but loses the ability to pass in a dynamically allocated buffer
template <size_t len>
char *convert(std::string str, char (&buf)[len])
{
memcpy(buf, str.data(), len - 1);
buf[len - 1] = '\0';
return buf;
}
Usage:
std::string str = "Hello";
// Use buffer we've allocated
char buf[10];
convert(str, buf);
// Use buffer allocated for us
char *buf = convert(str);
delete [] buf;
// Use dynamic buffer of known length
buf = new char[10];
convert(str, buf, 10);
delete [] buf;