Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a char* be moved into an std::string?

Say I have something like this

extern "C" void make_foo (char** tgt) {
  *tgt = (char*) malloc(4*sizeof(char));
  strncpy(*tgt, "foo", 4);
}

int main() {
  char* foo;
  make_foo(&foo);
  std::string foos{{foo}};
  free(foo);
  ...
  return 0;
}

Now, I would like to avoid using and then deleting the foo buffer. I.e., I'd like to change the initialisation of foos to something like

  std::string foos{{std::move(foo)}};

and use no explicit free.

Turns out this actually compiles and seems to work, but I have a rather suspicious feel about it: does it actually move the C-defined string and properly free the storage? Or does it just ignore the std::move and leak the storage once the foo pointer goes out of scope?

It's not that I worry too much about the extra copy, but I do wonder if it's possible to write this in modern move-semantics style.

like image 986
leftaroundabout Avatar asked Jun 03 '18 12:06

leftaroundabout


People also ask

Is char * a string?

char* is a pointer to a character. char is a character. A string is not a character. A string is a sequence of characters.

Should I use std::string or * char?

Use std::string when you need to store a value. Use const char * when you want maximum flexibility, as almost everything can be easily converted to or from one.

Can you set a string to a char * C++?

You can't really "assign a string" to a char * , because although a char* parameter is sometimes referred to as a "string parameter", it isn't actually a string, it's a pointer (to a string).


2 Answers

std::string constructor #5:

Constructs the string with the contents initialized with a copy of the null-terminated character string pointed to by s. The length of the string is determined by the first null character. The behavior is undefined if s does not point at an array of at least Traits::length(s)+1 elements of CharT, including the case when s is a null pointer.

Your C-string is copied (the std::move doesn't matter here) and thus it is up to you to call free on foo.

A std::string will never take ownership.

like image 64
Hatted Rooster Avatar answered Oct 22 '22 09:10

Hatted Rooster


tl;dr: Not really.

Pointers don't have any special move semantics. x = std::move(my_char_ptr) is the same as x = my_char_ptr. They are not similar in that regard to, say, std::vector's, in which moving takes away the allocated space.

However, in your case, if you want to keep existing heap buffers and treat them as strings - it can't be using std::string's, as they can't be constructed as a wrapper of an existing buffer (and there's small-string optimization etc.). Instead, consider either implementing a custom container, e.g. with some string data buffer (std::vector<char>) and an std::vector<std::string_view>, whose elements point into that buffer.

like image 31
einpoklum Avatar answered Oct 22 '22 10:10

einpoklum