【问题标题】:Is it legal to write to std::string?写入 std::string 是否合法?
【发布时间】:2009-04-17 15:06:59
【问题描述】:

在 std::string 中只有 const 成员来获取数据,如 c_str()。但是,我可以通过operator[] 获得对字符串第一个元素的引用,并且可以写入它。

例如,如果我有函数:

void toupper(char *first,char *last_plus_one);

我可以直接写入 vector 以获得指向第一个元素的指针:

vector<char> message // has "Some Message";
toupper(&message[0],&message[0]+message.size());

我可以用 std::string 做同样的事情吗?

string message="Some Message";
toupper(&message[0],&message[0]+message.size());

标准是否保证内存的位置实际上是线性的?即:

&(*(message.begin()+n)) == &message[n]

谢谢。

【问题讨论】:

  • 你不能简单地模板化 toupper 函数允许使用字符串迭代器而不是指针吗?
  • 如果可以,我不会问。想想我有一个大型的 3rd pary 库,它可能支持 unicode 或其他东西,并且它们的 api 与指针一起工作。因为将其实现为模板的成本很高。
  • @jalf:我手头没有标准,但我相信 std::to_upper 正是您建议的。

标签: c++ string standards


【解决方案1】:

Herb Sutter 有话要说 (http://herbsutter.wordpress.com/2008/04/07/cringe-not-vectors-are-guaranteed-to-be-contiguous/#comment-483):

当前的 ISO C++ 确实需要 &str[0] 提供一个指向连续字符串数据的指针(但不一定以 null 结尾!),因此无论如何,实现者没有太多余地来拥有非连续字符串。对于 C++0x,我们已经采用了 std::string 内容确实必须连续存储的保证。详情见http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#530

Matt Austern 在参考文件 (http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#530) 中也说过类似的话。

因此,您似乎可以假设,一旦您调用 str[0],您确实会得到一个可修改的字符数组(但请注意,它不需要以空字符结尾)。

【讨论】:

  • 实际上从链接中我看到 C++03 不需要连续内存,但实际上没有其他实现。
  • 我知道最好不要怀疑 Sutter,但有没有人提到 &str[0] 需要产生指向连续数据的指针?
  • 根据 Austern 的说法,通过 operator[] 访问需要连续数组,通过迭代器访问则不需要(所以 &str.begin() 不会)。我不会和萨特或奥斯特恩争论,但我仍然没有足够的信心把“所以,看起来”黄鼠狼的话放进去。
  • 好吧,我明白你在说什么,我只是试着找到说明这一点的标准参考。
  • 我认为 Austern 和 Sutter 都暗示至少在 C++ 03 之前,std::string 不需要是连续的,但没有已知的实现有任何其他方式。底线是问题中的示例是“未定义的行为”。从库部分的开头搜索“连续”或“[0]”会直接通过“字符串”部分并在“向量”中停止。
【解决方案2】:

std::string 需要使用新的 c++0x 标准进行连续存储。目前这是未定义的行为。

【讨论】:

  • 是否存在使用非连续字符串的已知编译器? IE。我可以在 99% 的情况下联系起来吗(也许只是为特定的编译器做一些变通以防止复制开销)
  • 我一直认为拥有一个对这些类型的东西(过度)迂腐的编译器/库会很“整洁”。它会以困难/低效/意想不到的方式做事,同时仍然合规。
  • 几乎可以肯定是连续的 - 但 std::string 还存储诸如长度之类的东西,如果你这样做可能会无效。
  • 我似乎记得一位委员会成员(最有可能是 Sutter)对标准不需要连续存储字符串感到惊讶。他们打算有这个要求,它将在下一个标准中,我不知道任何没有连续字符串存储的实现。
  • 你为什么还要担心这些问题。使用迭代器,所有问题都消失了!!
【解决方案3】:

是的,您可以修改字符串。

您也可以在使用迭代器的算法中使用它。

您不能以与向量相同的方式使用它,因为不能保证元素位于连续的内存位置(但是:很快就会成为您附近的标准)。

因此,如果您修改方法以使用迭代器而不是指针,它应该可以工作。而且由于迭代器的行为与指针非常相似,因此代码更改应该可以忽略不计。

template<typename I>
void toupper(I first,I last_plus_one)
{
    // Probably the same code as you had before.
}


{
     std::string  s("A long string With Camel Case");

     toupper(s.begin(),s.end());
}

【讨论】:

    【解决方案4】:

    正如已经指出的那样,可以在使用迭代器的算法中使用字符串;可以使用std::transform 实现相同的大小写示例:- 考虑将字符串“s”转换为小写:

    int (*pf)(int)=tolower; //lowercase
    std::transform(s.begin(), s.end(), s.begin(), pf); 
    

    问候,

    【讨论】:

      【解决方案5】:

      我认为它会给你一个未定义的行为。使用 stringstream 写入,然后使用 str() 成员获取流的字符串。

      【讨论】:

      • 错了。您可以写入字符串。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-16
      • 1970-01-01
      • 2015-02-16
      • 2013-05-28
      • 1970-01-01
      • 2013-03-01
      相关资源
      最近更新 更多