2016-12-24 88 views
2

我想这个代码中的最后两行应该编译。每当预期字符串文字时,可以使用std :: string :: c_str()吗?

#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 
+0

您是否包含''?而且,'main()'总是返回'int'。 –

+1

字符串文字具有数组类型,而'c_str()'返回一个指针。有可能会有功能超载,可以说明差异(但相当不友好,使他们的行为显着不同)。 –

+0

'string(“value”).c_str()'的生存期非常有限。所以除非'const char *'的副本完成,否则你可能有悬挂指针。 – Jarod42

回答

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*,由于第二个构造函数过载声明为explicit,因此无法将其隐式转换为GenericStringRef<Ch>

您从编译器中获得的错误消息是由于它选择了另一个更接近匹配的过载AddMember而导致的。

+0

请注意,编译器在引用的诊断中反应的实际参数是一个文字或数组,声明为'char const [4]',而不是c_str()调用。 –

+0

@ Cheersandhth.-Alf编译器错误也是指参数1.因此,我的答案中的最后一句。 –

+0

好,所以基本上,'AddMember'方法接受字符串文字而不是'char'指针。 – GetFree

5

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

但是,如果您尝试呼叫的界面需要char阵列,我会感到惊讶。也就是说,在你使用它应该工作。这很可能需要包含<string>

+0

您也无法将c_str传递给期望char *(不是const),数组或不是的数组。而且你还必须小心,你传递给它的函数不会将指针存储在某个地方以备后用,这会编译但最终会炸毁。 –

+3

@JasonC:你无法将字符串字面值传递给期望char *的东西!特殊转换的C向后兼容性总是被弃用,并且被C++ 11删除。 –

3

即使该代码编译:

obj.AddMember("key2", string("value").c_str(), doc.GetAllocator()); 

你不能保证它是安全的。

std :: string :: c_str()返回的const char *将一直有效,直到此语句结束。

如果AddMember方法存储字符串本身的副本,一切都很好。如果它存储了一个指针,那么你注定了。您需要了解AddMember的内部工作原理,然后才能推断代码的正确性。

我怀疑作者已经想到了这一点,并已构建了要求,你要么在std::string对象(或同等学历)发送过载或文字字符串引用(template<std::size_t N> void AddMember(const char (&str)[N])

即使这不是他们记住,他们可能希望保护你不受自己的影响,以防你无意中发出无效指针。

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

+0

_您需要了解AddMember的内部工作原理,然后才能推断您的代码的正确性。 - - 您需要仔细阅读文档。但谨慎使用这种结构是一个很好的建议,我谨向图书馆的作者致敬。 –

2

重新

why is the return of .c_str() not equivalent to a string literal

甲文字串与在编译时已知大小的阵列的零终止的字符串。

c_str()会生成一个指向(第一个项)的指针,该指针指向一个数组,其大小仅在运行时已知。

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

  • 结合到数组的引用,

  • 使用sizeof操作者,和

  • 形成字符串文字的较大字面由编译时间级联(仅仅是为了将它们写)。

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


你引用的错误消息,

cannot convert parameter 1 from 'const char [4]' to 'rapidjson::GenericValue &

&hellip; 不符合您呈现代码

#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()呼叫的阵列。

+0

也许VC++不计算空终止? – GetFree

+0

@GetFree:它必须数它。它是数组大小的一部分。 –

+0

哦,你说得对,我刚刚意识到我在写这个问题的时候在''key''字符串中加了一个''1“'和''2”'。我会解决这个问题。 – GetFree

相关问题