我有一些Objective-C++来包装现有的C++库。C++库偶尔会给我std::string&
参数,我想将这些参数转换为nonnull
NSString
。几乎所有NSString
初始值设定项都返回nullable NSString
,除了:-initWithCharactersNoCopy:length:freeWhenDone:
和-initWithCharacters:length:
。但是,这两者都需要unichar *
,但std::string.c_str()
返回char *
。
如何从C++std::string
获取unichar *
,以便创建NSString * _Nonnull
?
不是重复的
其他问题只是想从std::string
转换为NSString
。我想知道是否可以在不产生null
NSString *
的情况下这样做,可能是通过在std::string
上调用方法来获得unichar *
。std::wstring_convert
看起来很有前途,但我不是一个C++开发人员,所以我还不知道如何开始。
可能的解决方案
经过进一步研究,我了解到std::string
只是一个std::basic_string<char>
,似乎你可以定义自己的std::basic_string
。我找到了一个类似的例子,可以转换为std::wstring
:
// std::string -> std::wstring
std::string s("string");
std::wstring ws;
ws.assign(s.begin(), s.end());
所以我把它改编成std::basic_string<unichar>
,编译得很好:
void Foo(const std::string& bar) {
std::basic_string<unichar> barUnichar;
barUnichar.assign(bar.begin(),
bar.end());
NSString * _Nonnull barNSString =
[NSString stringWithCharacters:barUnichar.c_str()
length:barUnichar.length()];
NSLog(@"bar: %@", bar);
}
我不介意从std::string
转换为std::basic_string<unichar>
执行不必要的复制,我想一旦我了解有关内存所有权规则的更多信息,我就可以更改上面的代码以使用C++-[NSString initWithCharactersNoCopy:length:freeWhenDone:]
。
可能的解决方案不好
乔·格罗夫在推特上说:
这将进行逐字节映射。它可能适用于 ASCII,但 会给你任何Unicode的垃圾。
让我们再试一次,看看它是否对您有帮助。您已经编辑了该问题以响应建议,它是重复的并添加了:
其他问题只是想从
std::string
转换为NSString
。我想知道是否可以在不产生null
NSString *
的情况下做到这一点......
直接答案:不
原因很简单:Objective-C库不能假设传递给它的任何指针都引用有效编码的C字符串,即使该指针是std::string
键入的。
现在你可能非常有信心,你的C++代码永远不会给你一个无效编码的字符串——可以说信心是合理的(但毕竟是C++;-))——所以相信空结果永远不会发生,但这并不能改变Objective-C库不能假设它不会发生的事实。
DIY答案:是的
尝试避免空值,例如尝试将std::string
转换为unichar *
等,就像您所考虑的那样,只是避免了这个问题 - 某处的某些代码必须处理检查编码或冒返回无效编码NSString
的风险。
虽然可以做到这一点,但与 DIY 方法相比,它既会更加复杂,并且可能会让您不知道无效编码会返回什么:只需在源代码中自己处理 null 返回并用其他内容替换它。例如:
std::string someCstring;
NSString *convertedString = @(someCstring.c_str()) ?: @"ERROR: C string is invalid UTF8";
在这里convertedString
永远不会nil
.
(如果你的 C 字符串不是 UTF8,你将需要使用另一个接受编码的NSString
初始化器。
呵呵