调用实例变量(即对象)的getter函数时实际发生了什么?

时间:2013-12-05 19:37:46

标签: c++ reference segmentation-fault const getter

最近我和一个导致SEGFAULT随机的函数不断争斗。在尝试找出问题后做了一些额外的工作后,我想出了以下内容:

所有代码都通过pastebin发布:

BUILD 1:这是原始代码,它会导致以下SEGFAULT(链接后给出) http://pastebin.com/huzcqnDA

段错误:

#0 6FC657AC libstdc++-6!_ZNKSs4_Rep12_M_is_leakedEv() (Z:\CPP Programming\CodeBlocks\MinGW\bin\libstdc++-6.dll:??)
#1 6FC89FDB libstdc++-6!_ZNSs4_Rep7_M_grabERKSaIcES2_() (Z:\CPP Programming\CodeBlocks\MinGW\bin\libstdc++-6.dll:??)
#2 6FC8C0E7 libstdc++-6!_ZNSsC1ERKSs() (Z:\CPP Programming\CodeBlocks\MinGW\bin\libstdc++-6.dll:??)
#3 0094A470 Carp::Sprite::Sprite(this=0x27fae8, s=...) (Z:/CPP Programming/Carperon/Source/Carp/Engine/StructL2.hpp:28)
#4 00944E98 Carp::Item::_spr(this=0x1277eb80) (Z:/CPP Programming/Carperon/Source/Carp/../Carp/Classes.hpp:59)
#5 00416219 Carp::WinBag::update(this=0x2857f8, o=false) (Z:\CPP Programming\Carperon\Source\Carp\Interface.cpp:60)
#6 00419304 Carp::GameUI::checkUpdate(this=0x2857e4) (Z:\CPP Programming\Carperon\Source\Carp\Interface.cpp:240)
#7 00401B7D Carp::GameApp::loopGame(this=0x2801ac) (Z:\CPP Programming\Carperon\main.cpp:35)
#8 00402145 _fu2041___ZSt4cout() (Z:\CPP Programming\Carperon\Source\Application.cpp:25)
#9 004017A9 main() (Z:\CPP Programming\Carperon\main.cpp:6)

BUILD 2:这是当前的构建,目前导致编译器错误,这让我觉得这可能是导致问题的原因。 http://pastebin.com/89gCjH5P

错误:

Z:\CPP Programming\Carperon\Source\Carp\Interface.cpp|57|error: no match for 'operator<<' in 'std::operator<< <std::char_traits<char> >((* &(& std::operator<< <std::char_traits<char> >((* &(& std::operator<< <std::char_traits<char> >((* &(& std::operator<< <std::char_traits<char> >((* & std::cout), ((const char*)"Item Info: ")))->std::basic_ostream<_CharT, _Traits>::operator<< <char, std::char_traits<char> >(a)), ((const char*)"\012ItemContainer: ")))->std::basic_ostream<_CharT, _Traits>::operator<< <char, std::char_traits<char> >(((const void*)((Carp::WinBag*)t|

当我调用Character中给出的getter函数时,实际发生了什么?我没有看到这里的问题,以及之前的Q&amp; As我发现没有解决问题,它们只会导致它在以后打破另一个随机函数。

我可以称之为最好的情况是Heisenbug,因为这只发生在我在处于DEBUG模式的程序中其他地方的无关SEGFAULT时。

我发现唯一可能的帮助就是对我的getter使用const-correctness,只是为了再次将相同的SEGFAULT带到板上(浪费时间进行编译)。

P.S。我的程序与Ogre3D具有静态链接,这使我的平均编译时间为5分钟(如果我更改特定标题,则超过7)。因此,我需要很长时间才能发布编辑/结果。

P.S。 Carp::WinBag与示例代码中给出的Carp::Interface相同(给出了错误的类名)

额外注意:我已经连续5天出现此问题。我的理智只能承担更多这个......

解决方案:我的情况是由于我自己在代码中的其他地方懒惰造成的:

ItemPtr temp(new Item(*listItem[1].get()));
temp->spawnDrop(Coord3(fRAND(-1,1),2,fRAND(-1,1)));
dropList.push_back(temp);
temp.reset(new Item(*listItem[2].get()));
temp->spawnDrop(Coord3(fRAND(-1,1),2,fRAND(-1,1)));
dropList.push_back(temp);
temp.reset(new Item(*listItem[3].get()));
temp->spawnDrop(Coord3(fRAND(-1,1),2,fRAND(-1,1)));
dropList.push_back(temp);

有了这个,我创建了一个指向新对象的指针,同时导致旧对象丢失(内存泄漏任何人?)。这导致了我后面在代码中遇到的所有问题,并且以正确的方式编写这个问题将解决它。

我无法相信在这么长时间后我再次这样做了,更糟糕的是没有意识到......对于其他任何不幸的人来说,假设这个有用,请不要。它会给你带来无穷无尽的压力:*

1 个答案:

答案 0 :(得分:2)

字符不保证Items已初始化为指针。当你调用它时,它只返回一个指针。如果该指针尚未初始化(或已初始化为错误的内存位置),则尝试访问该指针可能会导致seg错误:

Character c;
Intem* items = c._items();//get uninitialized ptr in c
items[foo];//seg fault (maybe)

当然,这不是您在通话中获得seg-fault的唯一方法。

你的getter调用实际发生的是你正在使用一个“this”指针,对“this”指针应用一个偏移量以找到“items”指针,并返回该值。但是,如果您的“this”指针无效,那么您可以获得seg错误。所以:

Character* c;//not inititialized
c->_items();//seg fault (maybe)

可以单独导致seg故障。

然而,并不总是发生seg故障:如果指针位置恰好是良好的内存,你将看不到seg错误,你将继续进入未定义的行为模式。

那么你究竟如何调试这些东西?必须承认,这是一个痛苦的屁股。这是人们不喜欢C和C ++的主要原因之一,我不认为这里的大多数人会为你寻找它。

调试模式下的大多数编译器都会强制将未初始化的指针指向某个值。有时值是hexspeak(我最喜欢的是0xBADF00D)。所以看看你的指针值。 Visual Studio初始化指向0xccccccccccccc。

的指针

但是,避免此类问题的最佳方法是使未初始化的指针无法实现。使用矢量和参考。当你必须使用指针时,坚持使用智能指针。在构造函数和析构函数中使用RAIIdesign模式。遵循规则3(或c ++ 11中的3-5规则)。你永远不会(好吧,你很少“)很少需要寻找无效的价值,因为你已经让它们难以存在。