为什么此指针被错误地复制?为什么分段错误没有更早发生
Why Is This Pointer Being Copied Incorrectly? Why Does The Segmentation Fault Not Occur Earlier?
我正在调试一个程序,该程序从二进制文件中读取数据并将其放入TaggerDataUnigram
对象的字段中,TaggerDataUnigram
是从TaggerData
派生的类。所有读取操作都会读取文件中指定的许多数据对象,并将这些对象放入 TaggerData
的字段中。因此,我定义了一个函数ReadForNumberToRead
,它将文件和Reader*
作为参数,Reader
函数的基类,用于定义如何从文件中读取数据。每个Reader
导数都采用TaggerData*
作为参数,并将指针的值存储为成员。不幸的是,TaggerData
使用 getter 和 setter,但 getter 返回对字段的引用。因此,例如,OpenClassReader
通过tagger_data_pointer_->getOpenClass()
访问TaggerData::open_class
。
示例:ForbiddingRuleReader
的构造函数:
ForbiddingRuleReader::ForbiddingRuleReader(
FILE*& tagger_data_input_file_reference,
TaggerData* tagger_data_pointer)
: Reader(tagger_data_input_file_reference, tagger_data_pointer) {}
tagger_data_pointer_
是Reader
的protected
成员。
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);
}
不用说,TaggerDataUnigram
对象并没有超出范围。
OpenClassReader
和ForbiddingRuleReader
都可以完美地工作;它们将文件的副本存储为字段,并TaggerData*
为字段,并连续从文件中读取数据并将其放入TaggerData
中各自的字段中。构建ArrayTagReader
时出现问题。尽管共享相同的构造函数并且使用方式与ForbiddingRuleReader
相同,但有些事情出了很大的错误——tagger_data_pointer_
并没有指向内存中与构造对象TaggerData* tagger_data_pointer
相同的位置!
Breakpoint 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()
时,程序遇到了分割错误,特别是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_pointer
被错误地复制?为什么程序在尝试写入无效内存后没有立即遇到分段错误?如何解决此问题?谢谢你的时间。
更新:这些可能很有用:
void 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()();
}
}
更新:不知何故,我错过了ArrayTagReader
的tagger_data_poiner_
宣言;使指针const
生成编译器错误,这引起了我的注意。我仍然不明白的是为什么:
- 编译器没有抱怨使用未初始化的指针。
- 程序在尝试修改时没有遇到分段错误,例如
tagger_data_poiner_->getArrayTags()
.
tagger_data_pointer_
不指向内存中与构造对象时使用的TaggerData* tagger_data_pointer
相同的位置"
这通常意味着该值已被覆盖。一个非常常见的原因是前面字段中的缓冲区溢出,或者不太常见的是后面字段中的缓冲区溢出_under_flow。它还解释了为什么这是一个只发生在两个类中的一个中的问题;另一个类有其他邻居。不过,并非所有覆盖都是缓冲区溢出/下溢。无效的类型转换是另一个可能的问题。
既然你不是要改变指针,那就让它const
。第二种调试技术是将字段替换为包含 3 个相同副本的数组。创建一个函数,该函数检查所有三个是否相同,如果不是,则抛出,否则返回单个值。在取消引用指针的位置,现在调用此检查函数。这为您提供了检测更改的确切性质的好机会。更花哨的算法会添加具有已知值的额外填充数据。
尽管共享相同的构造函数并且使用方式与ForbiddingRuleReader相同
我不确定你为什么认为这些很重要,但我可以告诉你,根据C++标准,这些与两种类型是否具有相同的内存布局或是否可以在它们之间reinterpret_cast
(或道德等价)完全无关。
我无法正确阅读您的代码,因为除了"UPDATE"之外的所有内容都非常混乱,除了作者之外,任何人都很难阅读。更新部分似乎还可以。因此,我将介绍一些有关使用指针进行复制的提示(因为我最近看到很多人都犯了这些错误),也许它会有所帮助。
-
确保您不只是从未"标记为"分配的内存位置复制或复制到内存位置。换句话说,如果你有一个指针,并且你只是将数组中的数据复制到它指向的内存位置,那么没有什么可以阻止你的程序或当前在计算机上运行的其他程序修改该区域。您首先分配空间(使用 new、malloc 等),然后您可以从/复制到它。
type *p = new type[size];
-
即使您满足第 1 点,也要确保复制的空间不超过
size
。
关于这个问题的建议,通过评论(我不能评论 ATM)......
你可能是一个非常好的程序员。但你会犯错误。这意味着你必须找到它们。这意味着你应该保持代码整洁。但保持整洁还有更重要的原因。阅读您的代码的人并不真正知道所有内容"应该"在哪里。对他们来说,阅读混乱的代码是不可能的任务。这很重要,因为有人可能不得不继续为公司处理您的代码。或者,如果你正在寻求其他程序员的帮助,就像你现在所做的那样,你需要有人来找你。
对于代码中的每个子块(用 { } 覆盖),缩进应该是 1 个制表符或 4 个空格(你不能在 StackOverflow 上使用制表符),除非该块为空。
如果指令由于长度而在下一行继续,它也应该缩进。在这种情况下,您还可以添加其他制表符或空格,以使所有内容看起来都不错。例如,如果你有一个足够长的公式,可以分成 3 行,你可以让每一行从第一行的"="开始。
"UPDATE"部分看起来比其他部分好得多,但您仍然应该使用 4 空格缩进而不是 2 空格缩进。
- 我的字符计数代码计算错误.为什么
- C++ 错误 为什么这个矢量不输出?
- 当在函数调用中递增值时,程序正常工作,但是如果我们在单独的行中增加值而不是呼叫函数,则会出现错误.为什么
- 我正在将QPixmap传递给QAbstractButton::setIcon而不是QIcon,但我没有得到错误...为什么?
- 在 ZeroMQ 中绑定订阅者套接字并连接发布者套接字会在代码运行时给出错误.为什么
- 分段错误:为什么这里的数组索引越界了
- Box2D不寻常的错误.为什么 0阻止错误
- c++分段错误:为什么这个程序给出运行时错误(SIGSEGV)
- 链接列表错误 - 为什么头和尾引用指向相同地址
- VC++的一个大错误?为什么初始值设定项列表不对结构进行值初始化
- 分配大量内存会产生错误?为什么
- 得到一个段错误.为什么
- 变量名称与函数名称相同,导致编译器错误.为什么
- 访问在相应类的静态函数中创建的对象的私有成员变量不会导致错误.为什么?
- Qt5:此代码使用msvc2012编译正常,但使用MinGW编译时出现错误..为什么?
- 奇怪的错误-为什么编译器试图调用复制构造函数
- 我在使用 std::map 时收到此错误.为什么
- 我写了这个程序来反转链表中的元素,在编译这个程序后,在reverse()中显示错误.为什么
- Valgrind报告写入错误?为什么?
- 编译器错误 - 为什么我不能在Sublime Text 2中构建C++?