2016-12-29 77 views
2

我做一个DLL在C++和我得到这个错误我第二次调用一个函数:调试断言失败的类的析构

调试断言失败表达式:_BLOCK_TYPE_IS_VALID(pHead-> nBlockUse)

我做了一些研究,这似乎当我delete的对象,我没有new

这里是我认为的代码失败

class tFont 
{ 
public: 
    tFont(char chars[], __int64 cods[], int count); 
    ~tFont(); 


    int fontCount = 0; 
    char* characters = NULL; 
    long long* codes = NULL; 

    std::vector<std::pair<char,long long>> exceptions; 


    char getCharacter(long long code); 


}; 

tFont::tFont(char chars[], long long cods[], int count) 
{ 
    characters = new char[count]; 
    codes = new long long[count]; 
    fontCount = count; 

    for (int i = 0; i < count; i++) 
    { 
     characters[i] = chars[i]; 
     codes[i] = cods[i]; 
    } 


} 


tFont::~tFont() 
{ 

     delete[] characters; 
     delete[] codes; 
} 
发生

错误发生后,视觉工作室停在delete[] characters;

我tryied这没有任何的运气

if (characters != NULL) 
{ 
    delete[] characters; 
} 
if (codes != NULL) 
{ 
    delete[] codes; 
} 

我只能创建这个类的一个instace作为静态对象

tFont* getCapFont() 
{ 
    static tFont *capFont = NULL; 

    if (capFont == NULL) 
    { 
     char characters[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; 
     long long codes[] = { 241136, 441, 183861, 102321, 45836, 5955, 19305, 7871, 220321, 102286 }; 
     int fontCount = 10; 

     capFont = new tFont(characters, codes, fontCount); 
     pair<char, long long> e; 
     e.first = '0'; 
     e.second = 24045; 

     capFont->exceptions.push_back(e); 
    } 

    return capFont; 
} 

为什么叫析构函数,即使我永远不会做delete capFont

谢谢!

EDIT2:我照“jarmod”之称,并引发该错误的时刻是当这个函数结束

void analysis::singleLineTextReader(tImage img, char result[], tFont font)

我说这happend我第二次调用该函数,这是可能的当singleLineTextReader结束时调用其参数font的析构函数?其在上文

+5

只是猜测,但请参阅[3/5/0规则](http://en.cppreference.com/w/cpp/language/rule_of_three)。我也建议看看['std :: vector'](http://en.cppreference.com/w/cpp/container/vector),['std :: unique_ptr'](http://en.cppreference。 com/w/cpp/memory/unique_ptr)和['std :: shared_ptr'](http://en.cppreference.com/w/cpp/memory/shared_ptr)。 –

+0

在各种方法中添加一些调试打印语句,看看发生了什么。这可能不是你的想法。另外,在调用delete之前,没有必要绝对需要测试NULL,但是在调用delete之后将空指针置零是一种很好的做法(并且可以选择在删除它之前声明它不是null,以便在您意外地捕获编码错误双删除一个指针)。 – jarmod

+2

Edit2之后:'singleLineTextReader'通过值*获取它的参数*,这意味着它创建了一个字体的副本。该副本将包含在构造函数中创建的指针的副本,并且这些副本将在析构函数中被删除。之后,原始字体对象将包含悬挂指针。 –

回答

2
void analysis::singleLineTextReader(tImage img, char result[], tFont font) 

注意所描述的静态对象font通过值传递。你不通过一个指针。你不通过对它的引用。您通过其

所以你通过singleLineTextReader a tFont通过复制构建一个你传递给它的对象创建的对象。当副本的析构函数运行时,它会销毁底层对象的成员。当你再次这样做时,你正在销毁已经被破坏的物体。

遵守3/5/0规则。不需要时不要复制对象。

并且不要使用new/new[]除非你别无选择。在这里你可以使用各种其他的东西,如矢量。

+0

谢谢!这是解决方案 我将从现在开始使用更多的指针 – Lolrapa

+0

这里的正确教训是少**指针**,拥有原始指针是nono – sp2danny

+1

(facepalm在“我将使用更多的指针”)改为使用智能指针。如果除了char * characters = NULL;而不是'char * characters = NULL;'你编写'std :: unique_ptr 个字符;'(其中默认构造为NULL隐含)并且删除'delete []个字符;'then(1)意外地复制副本将不再可行,并且(2)由于天真的析构函数逻辑而导致的异常安全性的缺乏简单地消失。如果你类似地写'std :: unique_ptr 代码;'那么编译器会完全自动地为你写析构函数。 –