为什么这个指针被错误复制?为什么早期不会出现分段错误?

时间:2015-01-05 04:08:17

标签: c++ pointers constructor gdb initialization

我正在调试一个程序,该程序从二进制文件读取数据并将其放入TaggerDataUnigram对象的字段中,TaggerDataUnigram是从TaggerData派生的类。所有读取操作都读取文件中指定的许多数据对象,并将对象放入TaggerData字段中。因此,我定义了一个函数ReadForNumberToRead,它接受​​一个文件和一个Reader*作为参数,Reader是定义如何从文件中读取数据的仿函数的基类。每个Reader导数都以TaggerData*作为参数,并将指针的值存储为成员。不幸的是,TaggerData使用getter和setter,但getter返回对字段的引用。因此,例如,OpenClassReader通过TaggerData::open_class访问tagger_data_pointer_->getOpenClass()


示例:ForbiddingRuleReader' s构造函数:

ForbiddingRuleReader::ForbiddingRuleReader(
        FILE*& tagger_data_input_file_reference,
        TaggerData* tagger_data_pointer)
        : Reader(tagger_data_input_file_reference, tagger_data_pointer) {}

tagger_data_pointer_protected的{​​{1}}成员。

Reader

即可。 。 。以及Reader::Reader(FILE*& tagger_data_input_file_reference, TaggerData* tagger_data_pointer) : TaggerDataFileInputOutput(tagger_data_input_file_reference), tagger_data_pointer_(tagger_data_pointer) {} // tagger_data_pointer_ is initialized. 的相同构造函数:

ArrayTagReader

他们的用法同样如此:

ArrayTagReader::ArrayTagReader(FILE*& tagger_data_input_file_reference,
                               TaggerData* tagger_data_pointer)
        : Reader(tagger_data_input_file_reference, tagger_data_pointer) {}

毋庸置疑, void TaggerDataUnigram::ReadTheForbiddingRules( FILE*& unigram_tagger_data_input_file_reference) { ForbiddingRuleReader forbidding_rule_reader( unigram_tagger_data_input_file_reference, this); ReadForNumberToRead(unigram_tagger_data_input_file_reference, &forbidding_rule_reader); } [. . .] void TaggerDataUnigram::ReadTheArrayTags( FILE*& unigram_tagger_data_input_file_reference) { ArrayTagReader array_tag_reader(unigram_tagger_data_input_file_reference, this); ReadForNumberToRead(unigram_tagger_data_input_file_reference, &array_tag_reader); } 对象不会超出范围。


TaggerDataUnigramOpenClassReader都完美无缺;它们将文件的副本和ForbiddingRuleReader存储为字段,并从文件中连续读取数据并将其放入TaggerData*中的相应字段中。构造TaggerData时会出现问题。尽管共享一个相同的构造函数并且使用与ArrayTagReader相同的方式,但 出现了严重错误 - ForbiddingRuleReader并未指向内存中与{{1}相同的位置该对象是用!

构建的
tagger_data_pointer_

TaggerData* tagger_data_pointerBreakpoint 1, ArrayTagReader::ArrayTagReader (this=0x7fffffffd640, tagger_data_input_file_reference=@0x7fffffffd720: 0x62a730, tagger_data_pointer=0x7fffffffd8c0) at array_tag_reader.cc:10 10 : Reader(tagger_data_input_file_reference, tagger_data_pointer) {} (gdb) print tagger_data_pointer $1 = (TaggerData *) 0x7fffffffd8c0 <---------- (gdb) continue Continuing. Breakpoint 2, ArrayTagReader::operator() (this=0x7fffffffd640) at array_tag_reader.cc:12 12 void ArrayTagReader::operator()() { (gdb) print tagger_data_pointer_ $2 = (TaggerData *) 0x7fffffffd720 <---------- 中,OpenClassReader等于ForbiddingRuleReader

奇怪的是,即使指针明显无效,也不会立即导致错误。

tagger_data_pointer_

然而,在第一次调用tagger_data_pointer时,程序遇到分段错误,特别是Breakpoint 3, ArrayTagReader::operator() (this=0x7fffffffd640) at array_tag_reader.cc:12 12 void ArrayTagReader::operator()() { (gdb) print *tagger_data_pointer_ $3 = {_vptr.TaggerData = 0x62a730, open_class = std::set with 0 elements, forbid_rules = std::vector of length 275736, capacity -17591907707330 = {{tagi = -1972060027, [. . .] 。这并不奇怪;虽然TagIndexReader::operator()&#39; s SIGSEGV有效,但TagIndexReader对象的很大一部分已被泄露。

tagger_data_pointer_

为什么TaggerDataUnigram被错误地复制?为什么程序在尝试写入无效内存后不会立即遇到分段错误?我该如何解决这个问题? 谢谢你的时间。


更新 这些可能很有用:

Breakpoint 4, TagIndexReader::operator() (this=0x7fffffffd650) at tag_index_reader.cc:7
7   void TagIndexReader::operator()() {
(gdb) print tagger_data_pointer_
$16 = (TaggerData *) 0x7fffffffd8c0 <---------- This is the correct value.
(gdb) print *tagger_data_pointer_
$17 = {_vptr.TaggerData = 0x41e5b0 <vtable for TaggerDataUnigram+16>, 
  open_class = std::set with 6467592 elements<error reading variable: Cannot access memory at address 0x5200000051>,

更新 不知何故,我错过了tagger_data_pointervoid ArrayTagReader::operator()() { std::wstring array_tag = Compression::wstring_read( tagger_data_file_reference_); tagger_data_pointer_->getArrayTags().push_back(array_tag); } void ReadForNumberToRead( FILE* tagger_data_input_file_reference, Reader* pointer_to_a_reader) { for (int unsigned number_to_read = Compression::multibyte_read(tagger_data_input_file_reference); number_to_read != 0; --number_to_read) { pointer_to_a_reader->operator()(); } } 的声明;使指针tagger_data_poiner_生成了引起我注意的编译器错误。我仍然不明白的原因是:

  1. 编译器没有抱怨使用未初始化的指针。
  2. 尝试修改例如,程序没有遇到分段错误ArrayTagReader

3 个答案:

答案 0 :(得分:0)

  

尽管共享一个相同的构造函数并且使用与ForbiddingRuleReader

相同的方式

我不确定为什么你认为这些很重要,但我可以告诉你,根据C ++标准,这些与两种类型是否具有相同的内存布局或者是否可以{{1}无关他们之间的(或道德等同物)。

答案 1 :(得分:0)

我无法正确阅读您的代码,因为“更新”之外的所有内容都非常混乱,除了作者之外,其他任何人都很难阅读。 UPDATE部分似乎没问题。因此,我将简单介绍一些使用指针进行复制的技巧(正如我最近看到很多人犯了这些错误)并且可能会有所帮助。

  1. 确保您不仅仅是从未被“标记”为已分配的内存位置进行复制。换句话说,如果你有一个指针而你只是将数组中的数据复制到它所指向的内存位置,那么你的程序或当前在计算机上运行的其他程序就不会停止修改该区域。您首先分配空间(使用new,malloc等),然后您可以从/向它复制。

    type *p = new type[size];

  2. 即使您对第1点满意,也请确保复制的空间不超过size

  3. 关于这个问题的建议,通过评论(我无法评论ATM)......

    你可能是一个非常优秀的程序员。但你会犯错误。意思是你必须找到它们。这意味着你应该保持你的代码整洁。但是整洁的原因还有很多关键的理由。阅读代码的人并不真正知道“应该”应该在哪里。对于他们来说,阅读杂乱的代码是不可能的任务。这很重要,因为有人可能不得不继续为您的代码继续为公司工作。或者,如果您正在寻找其他程序员的帮助,就像您现在正在做的那样,那么您需要有人来帮助您。

    对于代码中的每个子块(用{}覆盖),缩进应该是1个制表符或4个空格(不能在StackOverflow上使用制表符),除非该块为空。

    如果由于长度而在下一行继续执行指令,则还应该缩进。在这种情况下,您还可以添加其他选项卡或空格以使一切看起来不错。例如,如果你有一个足够长的方程式,可以分成3行,你可以让每一行都从第一行的'='开始。

    “UPDATE”部分看起来比其他部分好一些,但你仍然应该使用4空格缩进而不是2空格缩进。

答案 2 :(得分:0)

tagger_data_pointer_并未指向内存中与TaggerData* tagger_data_pointer对象构造的位置相同的位置”

这通常意味着该值已被覆盖。一个非常常见的原因是前一个字段中的缓冲区溢出,或者下一个字段中的_under_flow不太常见。它还解释了为什么这个问题只发生在你的两个类中的一个;另一类有其他邻居。但是,并非所有覆盖都是缓冲区上溢/下溢。无效的类型转换是另一个可能的问题。

由于您并不是要更改指针,请将其设为const。第二种调试技术是用3个相同副本的数组替换该字段。创建一个函数,检查所有三个是否相同,如果不相同则抛出,否则返回单个值。在您取消引用指针的位置,现在调用此检查功能。这使您有机会检测到更改的确切性质。更奇特的算法会添加具有已知值的额外填充数据。