【问题标题】:Interchanging const char* and std::string交换 const char* 和 std::string
【发布时间】:2011-10-26 21:37:32
【问题描述】:

我正在重构一个旧的 C 库,目前正在更改外部 API,以便它使用 std::string 而不是 const char*。

ColumnType Table::getColType(const char *name) const
{
    int id = getColumnId(name) ;
    return getColType(id) ;
}

and

int Table::getColumnId (const char * col_name) const
{
    unsigned int i = 0;

    while ((i < m_table.num_cols) && (strcmp(m_table.cols[i]->name, col_name) != 0) )
        i++;

    if (i < m_table.num_cols)
        return i;
    else
        return -1;
}

收件人:

ColumnType Table::getColType(const std::string& name_in) const
{
    const char* name = name_in.c_str();
    int id = getColumnId(name) ;
    return getColType(id) ;
}

and 

int Table::getColumnId (const std::string& col_name_in) const
{
    const char* col_name = col_name_in.c_str();
    unsigned int i = 0;

    while ((i < m_table.num_cols) && (strcmp(m_table.cols[i]->name, col_name) != 0) )
        i++;

    if (i < m_table.num_cols)
        return i;
    else
        return -1;
}

在新代码中,我将 const char* 传递给现在期望引用 const std::string 的函数。我知道 std::string 可以从 const char* 初始化,并且代码可以正确编译(没有警告等)。

但我只是想确保我不会做任何以后会伤害我的事情(I18n 问题除外)。

简而言之 - 做什么是“安全的”?

【问题讨论】:

  • 为什么要传递const char*,而不是string 本身?我唯一能想到的是每次调用都会有不必要的副本......
  • 遗憾的是,C++ 对象不能很好地跨越库边界。或者更具体地说,如果两侧使用不同的库、不同的编译器、不同的设置或一天中的不同时间编译,它可能会失败......
  • @MooingDuck,当然;不过,从他的 sn-p 看来,对接受 std::stringgetColumnId 的调用似乎传递了 const char* - 真的有点多余......
  • @Nim:我的错,没看到。 HomunculusReticulli:当你立即将它们转换回const char* 然后忽略它们时,为什么你有接受字符串的函数?这会强制复制不需要的副本。
  • @Nim:是的,我意识到正在制作额外的字符串副本——但我不想对 500 多个函数进行大规模重构。这是“第一次通过”(仅处理 API),一旦工作(确实如此),然后我打算清理内部(比如摆脱不必要的字符串复制等)。

标签: c++ stl


【解决方案1】:

它是安全的,只要正确执行,它不应该造成任何伤害。

尽管如此,我认为我不建议继续这样做,除非你能指出实质性的好处。

可能更安全的方法是添加一个接受 const string&amp; 的函数,并直接传递给 const char* 函数。这样,您就可以让客户保留std::string&amp; 代码,而无需修改内部结构。

例如:

ColumnType Table::getColType(const std::string& name_in) const
{
    return getColType(name_in.c_str());
}

【讨论】:

  • 这是正确答案。外部库应在其接口上坚持使用最基本/原生/简单的类型(如果从您尚未考虑的内容链接,则可以从任何语言中理解的类型)。看看 .net 程序员在调用使用复杂类/结构作为参数的本机代码时遇到的麻烦。
  • @MartyTPS 我认为您提供的指导是很好的指导,但实际上问题应该决定解决方案。由开发人员决定是否在可用性/安全性和兼容性之间进行权衡,这应该取决于客户的需求。只是需要考虑的事情。
【解决方案2】:

1) getColType 中不需要从 std::string 中获取 c_str(),只需将 std::string& 直接传递给 getColumnId。

2) 您应该使用覆盖的equality operator 或直接使用std::string::compare 而不是strcmp。见

【讨论】:

  • 尽管,Mooing Duck 提出了一个很好的观点,即 std::string 跨编译器版本的兼容性。我并不是说你不应该这样做,但是当你购买它时,你应该了解它带来的一切。
  • 为什么是std::string::compare 而不是直观的operator==
  • @AndyT 好点。我会将其添加到答案中,但保留 compare 方法作为后备。
【解决方案3】:

当心 std::strings 包含 NULL。 C++ 类对它们很好; NULL 并不特殊。但是 C 字符串当然将其视为字符串结尾。以下是相同的:

if (std_string_a == std_string_b) { /* C++ way */ }

// vs.

const char *cstring_a = std_string_a.c_str(),
           *cstring_b = std_string_b.c_str();
if (0 == strcmp(a, b)) { /* C way */ }

当你混搭时,你不得不担心当 C++ 方式说假而 C 方式说真时会出现奇怪的错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-23
    • 1970-01-01
    • 2010-10-22
    • 1970-01-01
    相关资源
    最近更新 更多