【问题标题】:char* vs std::string in c++ [closed]C ++中的char *与std :: string [关闭]
【发布时间】:2010-10-22 12:29:34
【问题描述】:

什么时候应该使用std::string,什么时候应该使用char* 来管理C++ 中chars 的数组?

如果性能(速度)至关重要并且由于内存管理而愿意接受一些有风险的业务,您似乎应该使用char*

还有其他需要考虑的情况吗?

【问题讨论】:

    标签: c++ stl stdstring arrays


    【解决方案1】:

    我的观点是:

    • 如果不调用“C”代码,切勿使用 char *。
    • 始终使用 std::string:它更简单、更友好、优化、标准,可以防止出现错误,它已经过检查并证明可以工作。

    【讨论】:

      【解决方案2】:

      如果 std::strings 很大以避免复制,或者指向实例的指针,您可以通过引用传递它们,所以我看不出使用 char 指针有什么真正的优势。

      我使用std::string/wstring 或多或少地表示所有实际文本。 char * 虽然对其他类型的数据很有用,但您可以确定它会像应有的那样被释放。否则std::vector<char> 是要走的路。

      可能所有这些都有例外。

      【讨论】:

      • 两者在性能上有区别吗?
      • @vtd-xml-author:有些可能。直 char * 几乎没有开销。我不知道std::string 到底有多少开销,它可能取决于实现。我几乎不认为开销会比裸 char 指针大得多。由于我不拥有该标准的副本,因此我无法真正详细说明该标准所做的任何保证。任何性能差异都可能因要进行的操作而异。 std::string::size 可以将大小存储在字符数据旁边,因此比strlen 更快。
      • 为什么不将 std::string 用于非文本数据?它们不是以空值结尾的,因此您应该能够在其中存储任何您想要的东西。
      • @rodarmor 你可以存储你想要的任何东西,尽管它是有风险的,因为字符串是为空终止字符串设计的。您必须小心仅使用二进制安全操作,例如append(const string&)append(const char*, size_t) 而不是 operator+=()
      • 你确定吗?我知道许多操作会假设 char* 是一个以空字符结尾的字符串,但我想不出任何假设 std::string 不包含空值的操作。
      【解决方案3】:

      原始字符串用法

      是的,有时你真的可以做到这一点。当使用 const char *、分配在堆栈上的 char 数组和字符串字面量时,您可以完全不分配内存。

      与使用字符串或向量相比,编写此类代码通常需要更多的思考和谨慎,但使用适当的技术是可以做到的。使用适当的技术,代码可以是安全的,但是您始终需要确保在复制到 char [] 时,您要么对要复制的字符串的长度有一些保证,要么优雅地检查和处理过大的字符串。不这样做是导致 strcpy 系列函数不安全的原因。

      模板如何帮助编写安全的字符缓冲区

      至于 char [] 缓冲区的安全性,模板可以提供帮助,因为它们可以创建一个封装来为您处理缓冲区大小。像这样的模板被实现,例如由 Microsoft 提供 strcpy 的安全替换。这里的例子是摘自我自己的代码,真实的代码还有很多方法,不过这应该足够表达基本思想了:

      template <int Size>
      class BString
      {
        char _data[Size];
      
        public:
        BString()
        {
          _data[0]=0;
          // note: last character will always stay zero
          // if not, overflow occurred
          // all constructors should contain last element initialization
          // so that it can be verified during destruction
          _data[Size-1]=0;
        }
        const BString &operator = (const char *src)
        {
          strncpy(_data,src,Size-1);
          return *this;
        }
      
        operator const char *() const {return _data;}
      };
      
      //! overloads that make conversion of C code easier 
      template <int Size>
      inline const BString<Size> & strcpy(BString<Size> &dst, const char *src)
      {
        return dst = src;
      }
      

      【讨论】:

      • +1 表示“当使用 const char *、分配在堆栈上的 char 数组和字符串文字时,您可以完全不分配内存。”人们忘记了堆栈“分配”比堆快得多。
      • char* 字符串并不总是在堆栈中。 char *str = (char*)malloc(1024); str[1024] = 0;
      • @ColeJohnson 我不是这么说的,我只是说如果你想让你的字符串被堆栈分配,你需要将 const char * 与字符串文字结合使用,而不是 std::string。
      【解决方案4】:

      您必须使用char* 而不是std::string 的一种情况是您需要静态字符串常量。原因是您无法控制模块初始化其静态变量的顺序,并且来自不同模块的另一个全局对象可能会在初始化之前引用您的字符串。 http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Static_and_Global_Variables

      std::string 专业人士:

      • 为你管理内存(字符串可以增长,实现会为你分配更大的缓冲区)
      • 更高级别的编程接口,与其他接口配合得很好 的 STL。

      std::string 缺点: - 两个不同的 STL 字符串实例不能共享相同的底层缓冲区。因此,如果您按值传递,您总是会得到一个新副本。 - 有一些性能损失,但我会说除非您的要求很特殊,否则可以忽略不计。

      【讨论】:

      【解决方案5】:

      您应该考虑在以下情况下使用char*

      • 这个数组将被传入参数。
      • 您事先知道数组的最大大小(您知道或强加它)。
      • 您不会对此数组进行任何转换。

      其实在C++中,char*经常用于固定的小字,作为选项、文件名等...

      【讨论】:

      • 未传递数组,指向数组的指针。这就是指针的含义——指向对象的指针。
      【解决方案6】:

      何时使用 c++ std::string:

      • 总的来说,strings 比char* 更安全,通常当你使用char* 做事时,你必须检查事情以确保事情是正确的,在string 类中,所有这些都是为你完成的。
      • 通常在使用char* 时,您必须释放分配的内存,而string 不必这样做,因为它会在销毁时释放其内部缓冲区。
      • strings 与 c++ stringstream 配合得很好,格式化 IO 非常简单。

      何时使用 char*

      • 使用char* 可以让您更好地控制“幕后”发生的事情,这意味着您可以根据需要调整性能。

      【讨论】:

        【解决方案7】:

        如果您正在编写库,请使用 (const) char* 作为参数。 std::string 实现在不同的编译器之间有所不同。

        【讨论】:

        • 如果你用 C++ 编写库,std::string 的布局并不是你唯一需要担心的事情。两种实现之间存在许多潜在的不兼容性。只有在源代码中可用或为您正在使用的确切编译器编译时才使用 C++ 中的库。 C 库通常更具可移植性,但在这种情况下,您无论如何都没有 std::string。
        • 确实 std::string 不是唯一的问题,但要得出“仅在源代码中可用或为您正在使用的确切编译器编译的情况下才使用 C++ 中的库”的结论有点过分。 "有些组件系统可以与不同的编译器(例如 COM)一起正常工作,并且可以将 C 接口暴露给内部用 C++ 编写的库(例如 Win32 API)
        【解决方案8】:

        如果您想使用 C 库,则必须处理 C 字符串。如果您想将 API 公开给 C,同样适用。

        【讨论】:

          【解决方案9】:

          您可以期望 std::string 上的大多数操作(例如 find)尽可能优化,因此它们的性能可能至少与纯 C 对应物一样好。

          还值得注意的是,std::string 迭代器经常映射到指向底层 char 数组的指针。因此,就性能而言,您在迭代器之上设计的任何算法本质上都与基于 char * 的相同算法相同。

          需要注意的事情是,例如。 operator[] - 大多数 STL 实现不执行边界检查,应将其转换为对底层字符数组的相同操作。 AFAIK STLPort 可以选择执行边界检查,此时此运算符会慢一些。

          那么使用 std::string 有什么好处呢?它使您免于手动内存管理;调整数组大小变得更容易,而且您通常不必考虑释放内存。

          如果您在调整字符串大小时担心性能问题,有一个reserve 函数可能对您有用。

          【讨论】:

            【解决方案10】:

            如果您在文本等中使用字符数组,则使用 std::string 更灵活且更易于使用。如果您将其用于数据存储等其他用途?使用数组(首选向量)

            【讨论】:

              【解决方案11】:

              即使性能至关重要,您也最好使用vector&lt;char&gt; - 它允许提前分配内存(reserve() 方法)并帮助您避免内存泄漏。使用 vector::operator[] 会导致开销,但您始终可以提取缓冲区的地址并对其进行索引,就像它是 char* 一样。

              【讨论】:

              • 但是最好使用某种典型的字符串功能,并且可以选择指定存储策略。为此,请参阅我的答案中的链接。
              • 这不是真的。如果您认为向量将被分配在连续的内存空间中,那么重新分配(以增加向量大小)根本不会有效,因为它意味着前一个块的副本。
              • 我误解了您的回答,因为您使用向量而不是 char*,而不是字符串...在这种情况下,我同意。
              • 在 operator[] 的使用中不应该有开销。例如,请参阅stackoverflow.com/questions/381621/…
              【解决方案12】:

              AFAIK 在内部大多数 std::string 实现写入时复制,引用计数语义以避免开销,即使字符串不是通过引用传递。

              【讨论】:

              • 这已不再正确,因为写入时复制会在多线程环境中导致严重的可伸缩性问题。
              • 至少对于 GCC 的 STL 实现来说是这样的。
              猜你喜欢
              • 2016-06-10
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-06-17
              • 2016-09-12
              • 1970-01-01
              相关资源
              最近更新 更多