15

In C i used strcpy to make a deep copy of a string, but is it still 'fine' to use strcpy in C++ or are there better alternatives which i should use instead ?

Aerus
  • 4,332
  • 5
  • 43
  • 62

4 Answers4

25

I put this in the comment above, but just to make the code readable:

std::string a = "Hello.";
std::string b;
b = a.c_str();   // makes an actual copy of the string
b = a;           // makes a copy of the pointer and increments the reference count

So if you actually want to mimic the behavior of strcpy, you'll need to copy it using c_str();

UPDATE

It should be noted that the C++11 standard explicitly forbids the common copy-on-write pattern that was used in many implementations of std::string previously. Thus, reference counting strings is no longer allowed and the following will create a copy:

std::string a = "Hello.";
std::string b;
b = a; // C++11 forces this to be a copy as well
Zac Howland
  • 15,777
  • 1
  • 26
  • 42
  • I don't think you can say "`c_str()` makes a copy": it only returns the raw `char*` data. This data is then passed to the std::string constructor which performs the actual copy. If it was not copied, then b would be invalidated as soon as a went of scope or was destroyed. – Quentin Pradet Feb 27 '13 at 09:36
  • 2
    I didn't say `c_str()` makes a copy. I said `b = a.c_str()` makes a copy of the string. `c_str()` is not the focus of the operation; the copy-assignment operator is. – Zac Howland Mar 12 '13 at 15:27
  • I asked for an edit to make the question clearer. Feel free to perform a rollback if anything's wrong. – Quentin Pradet Mar 13 '13 at 08:23
16

In C++ the easiest way is usually to use the std::string class instead of char*.

#include <string>
...
  std::string a = "Hello.";
  std::string b;
  b = a;

The line "b = a;" does the same thing you would usually do with strcpy.

kynnysmatto
  • 3,665
  • 23
  • 29
  • 4
    Other than that, strcpy is just as legal and dangerous in C++ as it is in C. – Euro Micelli Jan 20 '11 at 19:18
  • So it basically *always* makes a deep copy when you assign one string to another variable, ok thanks :) – Aerus Jan 20 '11 at 19:20
  • 25
    `std::string`'s `operator=` does not actually do a deep copy. It does a reference counted copy (and thus, does not do exactly what `strcpy` does). If you want to make a deep copy of a `std::string`, you need to call it like so: `std::string a = "Hello."; std::string b; b = a.c_str();` to force it to actually make a copy instead of just copying the pointers and incrementing the reference count. – Zac Howland Jan 20 '11 at 19:28
  • 3
    @Zac Howland, @Aerus: Not necessarily, and less so now that some time ago. Copy on write is an implementation detail that is allowed but not required by the language. While in the past some libraries used it, the fact is that it is inefficient in multithreaded environments, as it requires locking that will incur a cost regardless of whether copies have been made, making the overall performance worse in most scenarios. – David Rodríguez - dribeas Jan 20 '11 at 19:34
  • @David: Some implementations have changed this, but others either haven't or require you to set compiler flags telling the compiler which version of `std::string` to use. Using the `c_str()` version will work in either case, though. – Zac Howland Jan 20 '11 at 19:36
  • 2
    @Zac: I mostly use g++, where strings don't use copy-on-write. I have just looked over the VC2010 headers and the string implementation there does not use copy-on-write either. There is at least one question in SO stating that VC2008 does not have copy-on-write either (or at least not by default). My guess is that the few (if there are any) compilers that still have copy-on-write will remove it in the near future. Now the trend is towards multicore processing, and the expense of locking overweights the advantage of COW – David Rodríguez - dribeas Jan 20 '11 at 19:57
  • 1
    Since when does g++ NOT use copy-on-write strings? A simple test proves that g++ uses COW. Using c_str() in the assignment is the way to do deep copying since its implementation independent. – Rahly Jul 02 '13 at 13:18
  • @JeremyWalton: A simple test shows you're right http://coliru.stacked-crooked.com/view?id=5f8d05dac2b6c2a17f856a19d4968926-9ed7c815abc680c1206ac401fbd99c16. That's a bug in the library. As of C++11 that is specifically disallowed. – Mooing Duck Aug 21 '13 at 20:45
  • @MooingDuck: The standard may have changed, but there are implementations that haven't caught up to the standard yet. If you want to avoid potential issues, using std::string sCopy = sOriginal.c_str();` works in all of the last 3 versions of the C++ standard. – Zac Howland Aug 21 '13 at 22:27
  • @ZacHowland: `std::string sCopy(sOrigional.begin(), sOrigional.end());` also works in C++03 and C++11, but is less buggy. – Mooing Duck Aug 21 '13 at 22:36
  • @MooingDuck: Yes, it does the same thing, but it is no more nor no less buggy unless you are storing null-terminators in your string. – Zac Howland Aug 21 '13 at 22:44
  • @ZacHowland: "It's no more buggy unless..." – Mooing Duck Aug 21 '13 at 22:56
  • @MooingDuck: Yes, unless you do something that basically makes every other function not work for your entire data set as well. – Zac Howland Aug 22 '13 at 00:10
  • Not sure I like this, I've used copy-on-write is tons of multithreaded applications. You have to be careful just like any other object. It could be made safer, I guess, and without "locking". "In multithreaded systems, COW can be implemented without the use of traditional locking and instead use Compare-and-swap to increment or decrement the internal reference counter." Since by BEING in multiple threads, the string will always have more than one refcount, making the original ALWAYS the same. Any "changes" will create a new array. Incrementing/decrementing the refcount should be safe. – Rahly Sep 03 '13 at 22:55
6

If you're using c++ strings, just use the copy constructor:

std::string string_copy(original_string);

Or the assignment operator

string_copy = original_string

If you must use c-style strings (i.e. null-terminated char arrays), then yeah, just use strcpy, or as a safer alternative, strncpy.

Community
  • 1
  • 1
SuperElectric
  • 17,548
  • 10
  • 52
  • 69
  • Aah nice alternative, hadn't thought of that :) – Aerus Jan 20 '11 at 19:21
  • 1
    strncpy is not a safer alternative to strcpy. Not only does it have several problems of its own, but it's not even intended as a replacement to strcpy, despite the name. strlcpy is a closer match to what strcpy intends, but strcpy_s is likely the safest option. – Tyler Shellberg Mar 01 '23 at 16:49
3

You are suggested to use strcpy_s because in addition to the destination and source arguments, it has an additional argument for the size of the destination buffer to avoid overflow. But this is still probably the fastest way to copy over a string if you are using char arrays/pointers.

Example:

char *srcString = "abcd";
char destString[256];

strcpy_s(destString, 256, srcString);
Nick Banks
  • 4,298
  • 5
  • 39
  • 65