删除对模板化函数的永不运行调用,在运行时获取分配错误

时间:2010-04-26 21:11:34

标签: c++ templates memory-management compilation

我有一段从不运行的模板化代码,但是已经编译了。当我删除它时,程序的另一部分会中断。


首先,我对如何提出这个问题感到有些不知所措。所以我会尝试在这个问题上投入大量信息。

好的,所以,我完全重新设计了我的实验性核心库的测试项目。我在库中使用了很多模板恶作剧。当我删除“用户”代码时,测试给了我一个内存分配错误。经过相当多的实验,我把它缩小到这段代码(几百行):

void VOODOO(components::switchBoard &board) {   
     board.addComponent<using_allegro::keyInputs<'w'> >();
}

有趣的是,让我感到惊讶的是,似乎编译这个函数的行为(以及它随后使用的模板函数,以及那些使用的模板函数......),错误没有出现。 此代码未运行。类似的代码(相同,但对于不同的键值)发生在其他地方,但是在Boost TDD代码中。

我意识到我当然没有给你足够的信息来为我解决它;我尝试过,但它或多或少会螺旋式地进入大多数代码库。我认为我最需要的是“这就是问题所在”,“这里就是在哪里看”等等。由于这条线,在编译过程中会发生一些事情,但我对这一步开始寻找不够了解

Sooo,如果一个(大概)编译,但从未实际运行过一些模板化代码,如何删除,会导致另一部分代码失败?


错误:

Unhandled exceptionat 0x6fe731ea (msvcr90d.dll) in Switchboard.exe:
0xC0000005: Access violation reading location 0xcdcdcdc1.

调用堆栈:

operator delete(void * pUser Data)
allocator< class name related to key inputs callbacks >::deallocate
vector< same class >::_Insert_n(...)
vector< " " >::insert(...)
vector<" ">::push_back(...)

看起来这个向量可能无效,因为_MyFirst和类似的数据成员在调试器中显示0xcdcdcdcd的值。但是向量是一个成员变量......

更新:向量无效,因为它永远不会生成。我得到一个频道ID值stomp,这使我将一种类型的频道视为另一种频道。


更新

再次使用调试器进行搜索,似乎我的方法是为每个“频道”提供它自己的唯一ID,而不是给我一个唯一的ID:

inline static const char channel<template args>::idFunction() {
    return reinterpret_cast<char>(&channel<CHANNEL_IDENTIFY>::idFunction);
};

Update2:这两个是相同的:

slaveChannel<switchboard, ALLEGRO_BITMAP*, entityInfo<ALLEGRO_BITMAP*>
slaveChannel<key<c>, char, push<char>

Sooo,让另一个已编译的通道类型改变事物是有意义的,因为它会改变idFunctions的值?但为什么有两个具有相同值的idFunction?

2 个答案:

答案 0 :(得分:3)

你似乎把这个函数的地址作为一个字符返回?看起来很奇怪。 char的位数比指针小很多,因此很有可能得到相同的值。这可能会导致更改代码布局修复/破坏程序的原因

答案 1 :(得分:2)

作为一般答案(虽然aaa的评论暗示了这一点):当这样的事情影响是否发生错误时,它要么是因为(a)你错了而且它正在运行,或者(b)包含该代码恰好会影响编译程序中的代码,数据和内存布局,导致heisenbug从可见变为隐藏。

后者通常发生在涉及未定义行为的事情时。有时一个虚假的指针值会让你踩到一些代码(根据代码布局可能会或可能不重要),或者有时伪造的写入会踩到数据堆栈中可能会或可能不会的值是一个稍后使用的指针,等等。

举一个简单的例子,假设你有一个看起来像的堆栈:

float data[10];
int never_used;
int *important pointer;

然后你错误地写了

data[10] = 0;

然后,假设堆栈按线性顺序分配,你将踩踏never_used,这个bug将是无害的。但是,如果删除never_used(或更改某些内容,以便编译器知道它可以为您删除它 - 也许你删除一个从未调用过的函数调用它会使用它),那么它会踩到{{1}相反,当你取消引用它时,你现在会得到一个段错误。