【问题标题】:How do I pass an std::string to a function that expects char*? [duplicate]如何将 std::string 传递给需要 char* 的函数? [复制]
【发布时间】:2010-11-30 18:51:27
【问题描述】:

可能重复:
Can I get a non-const C string back from a C++ string?

我需要先转换它吗?我在另一篇文章中看到,如果函数需要 const char*,则可以使用 .c_str()。只是 char* 呢?

【问题讨论】:

  • 函数要求 char* 而不是 const char* 是否有原因?
  • foo(reinterpret_cast<char*>(&mystring)) - 很简单!有什么问题?
  • @Noah:这是我们需要能够将 cmets 否决的情况之一。请删除它。它让我的脚趾甲卷曲。
  • 这可能是您正在使用的特定示例,但我相信 winsock 库并不是那么 foobar'd(即我认为所有方法都采用 PCSTR)如果它是示例,那么您就是玩,养成将这样的垃圾代码更改为const char*std::string的习惯。

标签: c++ visual-studio-2010 visual-c++


【解决方案1】:
std::vector<char> buffer(s.begin(), s.end());
foo(&buffer[0], buffer.size());
s.assign(buffer.begin(), buffer.end());

【讨论】:

  • 虽然请注意,在实践中,有信誉的编译器确实使用string 的连续存储。至少根据标准委员会在决定保证basic_string 在 C++0x 中的连续性时进行的民意调查。 “信誉良好的编译器”定义为“任何在场的人都能想到的编译器”。
  • @Steve:也许吧。但是,这个问题的正确答案很可能应该是“修复const 问题”。
【解决方案2】:

没有办法从保证在所有平台上工作的字符串中获取 char*,因为string 不需要使用连续存储这一简单事实。

您最安全、最便携的做法是将字符串复制到确实使用连续存储(可能是vector)的地方,然后改用它。

vector<char> chars(my_string.begin(), my_string.end());
char* ptr = &chars[0];

如果您想变得不那么可移植且绝对不安全,您可以确认您的 string 实现确实使用了连续存储,然后可以使用这个:

&my_str[0]

但我会打任何为我工作的开发人员这样做。

编辑:

我知道目前没有已知的 STL 实现不将字符串数据存储在连续数组中,这将使&amp;my_str[0] 安全。在即将到来的 C++0x 标准中,这也是事实(我被要求说明这一点),要求存储是连续的。

有人建议,因为如果这些事实表明我的帖子实际上是不正确的。

自己决定,但我说不。这不在当前 C++ 标准中,因此不是必需的。在实践中,我仍然会按照我建议的方式做事,并且在任何代码审查中,我都会标记任何假定底层存储是连续的代码。

考虑一下。假设有一个关于 vtable 指针的问题。有人想检查一个类并通过查看 vtable 来获取指向虚函数的指针。我会立即告诉他们不要这样做,因为没有提到 如何 在 C++ 中实现虚拟方法。我知道的每个实现都使用 vtables,我想不出更好的方法来做到这一点。多态性很可能会永远使用 vtables 来实现。这样可以直接检查 vtable 吗?

IMO 否,因为这取决于未记录的实施细节。你无法控制它,它可能随时改变。即使您期望它永远不会改变,依赖这些实现细节仍然是糟糕的工程。

自己决定。

【讨论】:

  • c_str() 必须返回具有连续存储的字符串。所以const_cast&lt;char*&gt;(my_string.c_str()) 可移植的,但提出了const_cast 是否真的安全的问题。如果有任何疑问,vector 方式是安全的。
  • @aschepler:但std::string 被允许不返回指向其内部数据的指针。 (它可以返回一个指向刚刚分配/预留的某个区域的指针,以存储c_str() 的返回值,直到对字符串进行下一次更改。)因此,即使我们跳过这将调用 UB 的事实,它也可能根本不工作。
  • 哦,我不知何故忽略了函数可能想要修改字符串内容的可能性。
  • @aschepler:否则为什么要使用非const 指针?
【解决方案3】:

共有三种情况:


如果函数不在您的控制范围内,并且它修改了字符串,或者您没有也无法知道它是否修改了字符串:

然后,将字符串复制到临时缓冲区中,并将其传递给函数,如下所示:

void callFoo(std::string& str);
{
    char* tmp = new char str(str.length() +1);
    strncpy(tmp, str.c_str(), str.length());
    foo(tmp);
    // Include the following line if you want the modified value:
    str = tmp;
    delete [] tmp;
}

如果函数不在您的控制范围内,但您确定它不会修改字符串,并且不将参数作为 const 只是 API 的错误。

然后,您可以将const 强制转换并传递给函数

void callFoo(const std::string& str)
{
    foo(const_cast<char*> str.c_str());
}

您可以控制该功能(更改签名不会造成过度破坏)。

在这种情况下,将函数更改为接受 string&amp;(如果它修改了输入缓冲区)或 const char*const string&amp;(如果不接受)。

【讨论】:

    【解决方案4】:

    当一个参数被声明为 char* 时,它隐含地假定该函数将作为副作用对所指向的字符串进行修改。基于此以及 c_str() 不允许修改包含的字符串这一事实,您无法将 std::string 显式传递给此类方法。

    这样的事情可以通过以下方法来实现:

    #include <cstdlib>
    #include <string>
    #include <iostream>
    
    void modify_string(char* pz)
    {
        pz[0] = 'm';
    }
    
    class string_wrapper
    {
        std::string& _s;
        char* _psz;
        string_wrapper(const string_wrapper&);
        string_wrapper& operator=(const string_wrapper&);
    public:
    
        string_wrapper(std::string& s) : _s(s), _psz(0) {}
    
        virtual ~string_wrapper()
        {
            if(0 != _psz)
            {
                _s = _psz;
                delete[] _psz;
            }
        }
    
        operator char*()
        {
            _psz = new char[_s.length()+1];
            strcpy(_psz,_s.c_str());
            return _psz;
        }
    };
    
    
    int main(int argc, char** argv)
    {
        using namespace std;
        std::string s("This is a test");
        cout << s << endl;
        modify_string(string_wrapper(s));
        cout << s << endl;
        return 0;
    }
    

    【讨论】:

      【解决方案5】:

      如果你确定char*不会被修改,可以使用const_cast去掉const。

      【讨论】:

      • Soo Wei 是对的,但请记住,如果您在不确定是否正常的情况下这样做,您的程序可能会崩溃!
      • 字符串不需要使用连续存储,所以这可能行不通。
      • c_str() 应该给你一个连续的内存块——但显然是严格只读的,这就是为什么它是 const 的。该函数没有采用const char * 表示它要么写得非常糟糕,要么会修改字符串。
      • 在将它作为参数传递之前,我会创建一个字符串(或 char*)的副本。如果不知道函数的行为,字符串对象的状态很容易变得不一致
      • 保证 c_str() 的返回值是连续的,并且在下一次调用非常量成员函数之前一直可用,因此使用 const_cast 将起作用。
      【解决方案6】:

      这是一个肮脏的解决方案,但我想它可以工作

      std::string foo("example");

      char* cpy = (char*)malloc(foo.size()+1);

      memcpy(cpy, foo.c_str(), foo.size()+1);

      【讨论】:

      • 这没什么不好的。人们正在让它变得比它需要的复杂得多。好吧,使用 new 而不是 malloc,但想法保持不变。
      猜你喜欢
      • 2020-12-11
      • 2011-04-18
      • 2013-09-21
      • 1970-01-01
      • 2018-04-27
      • 1970-01-01
      • 1970-01-01
      • 2012-07-15
      • 1970-01-01
      相关资源
      最近更新 更多