代码之家  ›  专栏  ›  技术社区  ›  GetFree

只要需要字符串文本,就可以使用std::string::c_str()?

  •  4
  • GetFree  · 技术社区  · 8 年前

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

    #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<>
        ]
    

    编辑2:
    请忽略以下事实: .c_str() 被称为时间值。这个示例只是为了显示编译错误。实际代码使用字符串变量。


    编辑3:
    代码的替代版本:

    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 回复  |  直到 8 年前
        1
  •  5
  •   Dietmar Kühl    8 年前

    这个 std::string::c_str() 方法返回 char const* 字符串文字的类型为 char const[N] 哪里 N 字符串中的字符数(包括空终止符)。相应地 c_str() 可以 用于 全部的 可以使用字符串文字的地方!

    如果您尝试调用的接口需要 char 不过,这是一个数组。也就是说,在您的使用中,它应该起作用。您更可能需要包括: <string> .

        2
  •  4
  •   Richard Hodges    8 年前

    即使编译了此代码:

    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]) )

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

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

        3
  •  3
  •   D Drmmr    8 年前

    查看链接到的文档,您似乎试图调用 AddMember 拿两个 StringRefType s(和 Allocator ). StringRefType 是的类型定义 GenericStringRef<Ch> ,它有两个重载构造函数,每个构造函数有一个参数:

    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 .

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

        4
  •  2
  •   Cheers and hth. - Alf    8 年前

    重新

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

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

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

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

    • 绑定到对数组的引用,

    • 使用 sizeof 操作员,以及

    • 通过编译时串接字符串文字(简单地按顺序写入)形成更大的文字。

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


    您引用的错误消息,

    无法将参数1从“const char[4]”转换为“rapidjson::GenericValue&

    与您提供的代码不匹配

    #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() 呼叫