每当需要字符串文字时,是否可以使用std :: string :: c_str()?

时间:2016-12-24 13:32:57

标签: c++ casting c-strings string-literals rapidjson

我猜这个代码中的最后两行应该编译。

#include "rapidjson/document.h"

int main(){
    using namespace rapidjson ;
    using namespace std ;

    Document doc ;
    Value obj(kObjectType) ;
    obj.AddMember("key", "value", doc.GetAllocator()) ; //this compiles fine
    obj.AddMember("key", string("value").c_str(), doc.GetAllocator()) ; //this does not compile!
}
但是,我的猜测是错误的。一行编译而另一行不编译。

AddMember方法有几个变体,如文档here所示,但除此之外......为什么.c_str()的返回不等同于字符串文字?

我的理解是,在接受字符串文字的地方,你可以通过string::c_str(),它应该有用。

PS:我正在使用VC ++ 2010进行编译。

修改
缺少#include <string>不是问题。它已包含在document.h

这是错误:

error C2664: 'rapidjson::GenericValue<Encoding> &rapidjson::GenericValue<Encoding>::AddMember(rapidjson::GenericValue<Encoding> &,rapidjson::GenericValue<Encoding> &,Allocator &)'
: cannot convert parameter 1 from 'const char [4]' to 'rapidjson::GenericValue<Encoding> &'
    with
    [
        Encoding=rapidjson::UTF8<>,
        Allocator=rapidjson::MemoryPoolAllocator<>
    ]
    and
    [
        Encoding=rapidjson::UTF8<>
    ]

EDIT2:
请忽略在时间值上调用.c_str()的事实。此示例仅用于显示编译错误。实际代码使用字符串变量。

EDIT3:
替代版本的代码:

string str("value") ;
obj.AddMember("key", "value", doc.GetAllocator()) ; //compiles
obj.AddMember("key", str, doc.GetAllocator()) ; // does not compile
obj.AddMember("key", str.c_str(), doc.GetAllocator()) ; // does not compile

4 个答案:

答案 0 :(得分:5)

std::string::c_str()方法返回char const*。字符串文字的类型是char const[N],其中N是字符串中的字符数(包括空终止符)。相应地,c_str()的结果可以用于所有可以使用字符串文字的地方!

但是,如果您尝试调用的接口需要char数组,我会感到惊讶。也就是说,在你使用它应该工作。您更有可能需要加入<string>

答案 1 :(得分:4)

即使编译了这段代码:

[ViceroyTrace] [ICE][ERROR]     Send BINDING_REQUEST failed(C01A0041).
Not in connected state, so giving up for participant [47CD8292] on channel [0].

您不能保证它是安全的。

std :: string :: c_str()返回的const char *在此语句结束之前有效。

如果obj.AddMember("key2", string("value").c_str(), doc.GetAllocator()); 方法存储了字符串本身的副本,那么一切都很好。如果它存储指针那么你就注定了。在了解代码的正确性之前,您需要了解AddMember的内部工作原理。

我怀疑作者已经考虑过这个并构建了重载,要求您发送AddMember对象(或等效对象)或字符串文字引用(std::string

即使这不是他们想到的,他们也可能希望保护您免受自己的伤害,以防您无意中发送无效指针。

虽然看似不方便,但这个编译时错误表明程序可能有问题。这是对图书馆作者的致敬。因为编译时错误比运行时错误更有用。

答案 2 :(得分:2)

RE

  

为什么.c_str()的返回不等同于字符串文字

字符串文字是数组中以零结尾的字符串,其大小在编译时已知。

c_str()生成一个指向数组中以零结尾字符串(第一项)的指针,该数组的大小仅在运行时知道。

通常,字符串文字表达式将用于表达式衰减指向第一个项目的上下文中,但在某些特殊情况下它不会衰减。这些案例包括

  • 绑定到对数组的引用,

  • 使用sizeof运算符和

  • 通过编译字符串文字的时间连接形成一个更大的文字(只需按顺序编写)。

我认为这是一份详尽的清单。

您引用的错误消息,

  

无法将参数1从'const char [4]'转换为'rapidjson :: GenericValue&amp;

... 与您提供的代码不符

#include "rapidjson/document.h"

int main(){
    using namespace rapidjson ;
    using namespace std ;

    Document doc ;
    Value obj(kObjectType) ;
    obj.AddMember("key1", "value", doc.GetAllocator()) ; //this compiles fine
    obj.AddMember("key2", string("value").c_str(), doc.GetAllocator()) ; //this does not compile!
}

此代码中没有任何地方有三个字符的长字符串文字。

因此,“这个编译”和“这不编译”的说法不是很值得信赖。

  • 应该引用实际的错误消息和实际代码(其中至少有一个不是编译时的内容),

  • 应该引用您正在调用的函数的文档。

另请注意,编译器在引用的诊断中作出反应的实际参数是文字或声明为这样的数组,而不是c_str()调用。

答案 3 :(得分:2)

查看您链接到的文档,您似乎试图将AddMember的重载调用为两个StringRefType(以及Allocator)。 StringRefTypeGenericStringRef<Ch>的typedef,它有两个重载的构造函数只接受一个参数:

template<SizeType N>
GenericStringRef(const CharType(&str)[N]) RAPIDJSON_NOEXCEPT;

explicit GenericStringRef(const CharType *str);

传递字符串文字时,类型为const char[N],其中N是字符串的长度+ 1(对于空终止符)。可以使用第一个构造函数重载将其隐式转换为GenericStringRef<Ch>。但是,std::string::c_str()返回const char*,无法隐式转换为GenericStringRef<Ch>,因为第二个构造函数重载被声明为explicit

您从编译器获得的错误消息是由于它选择了AddMember的另一个重载,这是一个更接近的匹配。