【问题标题】:C++: Is it possible to detach the char* pointer from an std::string object?C++:是否可以从 std::string 对象中分离 char* 指针?
【发布时间】:2012-01-02 09:29:17
【问题描述】:

我正在使用 std::string 类型进行字符串操作。

但是,有时我需要保留原始 char* 指针,即使在原始 std::string 对象被销毁后(是的,我知道 char* 指针引用 HEAP 并且最终必须被处理掉)。

但是,似乎没有办法将原始指针从字符串中分离出来,或者是这样吗?

也许我应该使用另一个字符串实现?

谢谢。

编辑

伙计们,请不要将分离与复制混淆。分离的本质是让字符串对象放弃其对底层缓冲区的所有权。所以,如果字符串有detach 方法,它的语义会是这样的:

char *ptr = NULL;
{
  std::string s = "Hello world!";
  ptr = s.detach(); // May actually allocate memory, if the string is small enough to have been held inside the static buffer found in std::string.
  assert(s == NULL);
}
// at this point s is destroyed
// ptr continues to point to a valid HEAP memory with the "Hello world!" string in it.
...
delete ptr; // need to cleanup

【问题讨论】:

标签: c++ string stdstring


【解决方案1】:

不,不可能分离std::string::c_str()返回的指针。

解决方案:制作字符串的只读副本,并确保该副本的存在时间至少与您需要 char* 指针一样长。然后在该副本上使用c_str(),它会一直有效。

如果这不可行,那么您也无法释放char*。并且任何试图将该指针包装在 RAII 构造中的尝试都只会重新发明 std::string 的一部分。

【讨论】:

    【解决方案2】:

    std::string 通过std:allocator(或模板参数)分配。即使您可以分离原始存储,您也必须通过std::allocator 释放它。您当然希望 RAII 类正确地做到这一点。

    幸运的是,标准库中已经有了这样的 RAII 类。它叫做std::string

    因此,最接近“分离”功能的是swap。它将资源从字符串中分离出来,并将它们存储在以后可以正确释放的形式(即另一个字符串)中。在 C++11 中,移动赋值也是如此。

    std::string raii_for_ptr;
    const char *ptr = NULL;
    {
         std::string s = "Hello world!";
         raii_for_ptr.swap(s); // or raii_for_ptr = std::move(s)
         ptr = raii_for_ptr.c_str();
         assert(s == "");
    }
    
    // no need to cleanup
    

    如果您的目标是为自己创建调用 delete 的需求,那么 (a) 这很荒谬,因此 (b) 标准库对您没有帮助。无论如何,您可能需要delete[] 而不是delete。但由于字符串不是(直接)使用new 分配的,因此认为您可以使用delete[] 获取它们的内存并(直接)释放它是不合适的。

    因此,如果您的实际情况是您需要向一些预先存在的 API 传递一个缓冲区,该缓冲区将使用 delete[] 释放,那么您必须获取一个副本,就像您需要传递一些 pre - 现有 API 一个缓冲区,将使用 free 释放。

    【讨论】:

      【解决方案3】:

      使用c_str() 将字符串复制成C 风格的字符串。然后使用strcpy()

      【讨论】:

        【解决方案4】:

        您可以将字符串复制到新的字符数组中。

        std::string s = "My string";
        char *a = new char[s.size()+1];
        a[s.size()]=0;
        memcpy(a,s.c_str(),s.size());
        

        【讨论】:

          【解决方案5】:

          您可以使用 2 种东西,具体取决于您的需要。 string::c_str () 会将字符复制到 C 字符串中,然后您可以将其用于您需要的任何内容。 std::data () 将返回一个指向字符串的指针,但有两个问题:a) 它不像 C 字符串那样以 NULL 结尾,并且 b) 当 std::string 被删除时它会消失。所以在你删除原始对象后它不会一直存在。

          【讨论】:

          • c_str 在删除原始对象后也会消失。 C++11 中的 FWIW datac_str 返回指向内部缓冲区的空终止字符串。
          【解决方案6】:

          由于您应该始终知道谁拥有特定的内存部分,因此更改字符串所有权的唯一方法是复制它。最简单的方法是将字符串分配给另一个 std::string 变量。如果所有权经常更改(或者您根本无法清楚地确定哪个特定对象是所有者),您会想要使用支持引用计数的另一个字符串实现(或 std::string 的包装器),所以您不需要必须一直分配新的内存。

          【讨论】:

            【解决方案7】:

            你可以这样使用它:

            std::string str = "abcd";
            char* cStr = str.c_str();
            

            谢谢...:)

            【讨论】:

            • str 超出范围时,cStr 会发生什么?答案是——它变成了垃圾,因为c_str() 不会分离char* 指针,而是将各自的std::string 保留为缓冲区的所有者。分离的本质是字符串放弃它对缓冲区的所有权。很抱歉,您的回答非常非常错误。
            • @mark: 要做到这一点,你可以取得字符串的所有权,将解决问题。
            • 这并不总是可能的,因此这是我的问题。
            猜你喜欢
            • 1970-01-01
            • 2022-07-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-04-01
            • 2019-11-18
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多