109

I have an NSString object and want to convert it into a std::string.

How do I do this in Objective-C++?

gabor
  • 4,281
  • 8
  • 24
  • 20

3 Answers3

155
NSString *foo = @"Foo";
std::string bar = std::string([foo UTF8String]);

Edit: After a few years, let me expand on this answer. As rightfully pointed out, you'll most likely want to use cStringUsingEncoding: with NSASCIIStringEncoding if you are going to end up using std::string. You can use UTF-8 with normal std::strings, but keep in mind that those operate on bytes and not on characters or even graphemes. For a good "getting started", check out this question and its answer.

Also note, if you have a string that can't be represented as ASCII but you still want it in an std::string and you don't want non-ASCII characters in there, you can use dataUsingEncoding:allowLossyConversion: to get an NSData representation of the string with lossy encoded ASCII content, and then throw that at your std::string

Community
  • 1
  • 1
JustSid
  • 25,168
  • 7
  • 79
  • 97
  • 14
    Careful of encoding. While UTF-8 is generally a good choice, if the API you're working with expects, say, pure ASCII or the system codepage, you'll have to use `-cStringUsingEncoding:` instead. :) – Jonathan Grynspan Nov 03 '11 at 20:57
  • 13
    This is a memory leak if you don't delete it, the returned pointer is not an Objective-C reference counted object. In general you should avoid using operator new for std::string. – SiimKallas Jan 28 '14 at 12:42
  • This should not be the accepted answer and definitely not the first thing to consider when doing that conversion. – JBL Mar 01 '16 at 14:20
  • @JBL After only 4 years and a few weeks I went around to expand my answer. I hope it's more acceptable now. – JustSid Mar 17 '16 at 20:00
  • @JustSid I should have precised my opinion, but the other issue is the use of a pointer by default. As a matter of fact, a coworker with an ObjC background, with no C++ knowledge used that, without deleting, ending up in a memory leak. And more generally; wild `new`s are frowned upon, and a `std::shared_ptr` or `std::unique_ptr` should be preferred. – JBL Mar 17 '16 at 21:06
  • @JBL Whoa, thanks for pointing that out. The original answer used a pointer, a year ago that was changed to a non pointer answer but apparently it was rolled back. I'll edit the pointer out again, sorry. On the upside, I finally have proof that I'm providing people with bad advice on SO that they blindly copy and paste, I feel honoured :p – JustSid Mar 17 '16 at 21:08
  • @JustSid That's exactly one of the reason for why I wanted to point this out: as some people just come and blindly copy paste, that's a big incitement to make the answers as correct as possible... :P – JBL Mar 18 '16 at 09:57
50

As Ynau's suggested in the comment, in a general case it would be better to keep everything on the stack instead of heap (using new creates the string on the heap), hence (assuming UTF8 encoding):

NSString *foo = @"Foo";
std::string bar([foo UTF8String]);
Marco83
  • 1,181
  • 1
  • 10
  • 28
11

As noted on philjordan.eu it could also be that the NSString is nil. In such a case the cast should be done like this:

// NOTE: if foo is nil this will produce an empty C++ string

// instead of dereferencing the NULL pointer from UTF8String.

This would lead you to such a conversion:

NSString *foo = @"Foo";
std::string bar = std::string([foo UTF8String], [foo lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
Community
  • 1
  • 1
Bruno Bieri
  • 9,724
  • 11
  • 63
  • 92
  • 2
    This is tremendously useful. Worrying to see almost everyone is overlooking it. Y'all gona crash on NIL. – P i May 17 '18 at 23:54
  • This is definitely a much better answer. Btw, if you already have a string there's no need to invoke one more constructor and destructor for std::string. Just do: `strYouHave.assign([foo UTF8String], [foo lengthOfBytesUsingEncoding:NSUTF8StringEncoding])` – c00000fd May 13 '23 at 08:19