字符串的问题

Trouble with Strings

本文关键字:问题 字符串      更新时间:2023-10-16

我目前正在调试一个相当大的程序。当我来到以下代码行时:

value->binary_string = value_it->binary_string.substr(range->msb->value, range->size);

程序运行不正常。这里的value是指向一个结构的指针,该结构的成员名为binary_string,类型为std::string。当我在调试时到达这一行时,我看到:

value_it->binary_string = "00000000000000000000000000000111"
range->msb->value = 0
range->size = 32

执行这行代码后,value->binary_string为空!我甚至把线路改成了

value->binary_string = value_it->binary_string

但它仍然失败了!

当我在调试时到达这一行时,我的程序使用了大约100MB的内存,所以我不认为这是内存问题(尽管我正在运行Valgrind来验证这一点)。我使用的是Ubuntu 11.10、g++-4.6和libstdc++6。

以前有人遇到过这样的事情吗?我不知道为什么我的琴弦不起作用!

谢谢,

Sam

第1版:

值的类型为NumberInst,定义如下:

typedef std::string String;
struct NumberInst
{
    unsigned size;
    bool signed_;
    String binary_string;
    bool valid;
    unsigned value;
    NumberInst();
};

第2版:

看起来我把搜索范围缩小了一点。调试时,我尝试了一些打印命令:

print value_it->binary_string
"00000000000000000000000000000111"
print value_it->binary_string[31]
'1'
print value_it->binary_string.substr(0, String::npos)
""
print value_it->binary_string.substr(0, 1)
""

在这种情况下,substr似乎无法正常工作。然而,当我在主函数中测试substr时,它似乎可以正常工作。

我发现,当发生这样的"奇怪"事情时,通常有两个常见的原因:

  1. 你犯了一个简单的错误,只是忽略了它
  2. 某种内存损坏

要检查第一个原因,请仔细阅读违规代码,并有意识地决定阅读代码在做什么,而不是你认为它应该做什么。通过假设代码应该做一些实际上没有做的事情,很容易忽略明显的错误,尤其是在您已经查看了一段时间的代码中。例如,几个月前,我在调试一些东西,遇到了一个变量突然"神奇地"改变其值的问题。事实证明,我只是打印了错误的变量(啊!),如果我一直在阅读代码的实际内容,我会很快发现这一点。

内存损坏是一个很难发现的问题,因为它可能发生在问题出现之前的任何一段代码中。Valgrind并不保证会发现所有形式的腐败,请以这个问题为例。在调试模式下运行,设置内存监视点(如果你知道损坏总是发生在哪里)和其他与内存相关的工具可能会有所帮助,将问题降至最低……不断消除正在运行的代码,直到损坏没有发生。

这个问题是由一个非常微妙的错误引起的。在我的项目中:

NumberInst* number = new NumberInst;
number->binary_string.reserve(size);
for (unsigned i = 0; i < size; i++)
    number->binary_string[i] = ...;

std::out_of_range异常不会被抛出,因为我假设标准库将数组索引与字符串的容量(而不是字符串的大小)进行比较。在调试器中调用print将成功,因为它可能会遍历缓冲区,直到到达"\0"字符。然而

String str = number->binary_string

将失败,因为标准库很可能从[0,size)复制value_it->binary_string的缓冲区并添加一个"\0"字符。由于value_it->binary/string的大小为0,复制其内容将失败(substr和其他依赖于调用字符串大小的函数也将失败)。

换句话说,问题是由调用引起的

str.reserve(size);

而不是

str.resize(size);

谢谢大家的帮助!

Sam