Visual Studio C ++“ProjectName.exe已触发断点”等问题

时间:2016-02-05 00:57:28

标签: c++ visual-studio

我已经调查了这个问题,但我还没有得到一个好的答案,所以我想我会在这里问。

我正在研究C ++项目,它涉及一些内存操作(分配动态字符串数组,并使用placement new将内存地址和完整对象放在这些数组中)。

每次在Visual Studio中调试程序时,我都会遇到一个非常令人沮丧的问题:弹出的消息通常是“ProjectName.exe触发了断点”。有时会说“在0x0FFD66CB(ucrtbased.dll)中抛出异常2 - Kennel.exe:0xC0000005:访问冲突读取位置0xFFFFFFF5。”

以下是相关课程的代码

Cat.h

#ifndef CAT_H
#define CAT_H

#include <string>
#include "Kennel.h"

using std::string;

class Cat {
private:
    static Kennel catKennel;
    int _id;
    string _name;

    Cat(int i, const string& nm) : _name(nm) { // Note initializer list
        _id = i;
    }

    void* operator new(size_t size){
        return catKennel.allocate();
    }
public:
    static Cat* create(int id, const string& name) { // Factory method
        return new Cat(id, name);
    }

    void operator delete(void* loc) {
        catKennel.deallocate(loc);
    }
};

Kennel Cat::catKennel(sizeof(Cat), 5);

#endif

Kennel.h

#ifndef KENNEL_H
#define KENNEL_H

#include <cstddef>
#include <cassert>
#include <iostream>
#include <new>

class Kennel {
private:
    static const size_t _BUCKET_COUNT = 10;
    const size_t _BUCKET_SIZE;
    const size_t _ELEM_SIZE;
    char* buckets[_BUCKET_COUNT];
    //char** buckets;
    char* availableBlock;
public:
    Kennel(size_t elemSize, size_t bucketSize = 5);
    ~Kennel();
    void* allocate(); // Get a pointer inside a pre-allocated block for a new object
    void deallocate(void*); // Free an object's slot (push the address on the "free list") 
};

#endif

Kennel.cpp

#include "Kennel.h"

Kennel::Kennel(size_t elemSize, size_t bucketSize) : _ELEM_SIZE(elemSize), _BUCKET_SIZE(bucketSize) {
    //Set each element in buckets to nullptr.
    for (int i = 0; i < _BUCKET_COUNT; i++) 
        buckets[i] = nullptr;
}

Kennel::~Kennel() {
    //Delete each character array in buckets.
    for (int i = 0; i < _BUCKET_COUNT; i++) {
        if (buckets[i] != nullptr) 
            delete[] buckets[i];
    }
}

void* Kennel::allocate() {
    //If there is no available bucket: create a new one.
    if (availableBlock == nullptr) {
        //Find next array index in buckets array where we can create a new bucket.
        int nextNullBucketIndex = -1;
        for (int i = 0; i < _BUCKET_COUNT; i++) {
            if (buckets[i] == nullptr) {
                nextNullBucketIndex = i;
                break;
            }
        }
        assert(nextNullBucketIndex > -1); //If there is no space to create another bucket: exit.

        //Create a new bucket.
        buckets[nextNullBucketIndex] = new char(_BUCKET_SIZE * _ELEM_SIZE);
        availableBlock = buckets[nextNullBucketIndex];
        char* tempBlock = availableBlock;

        //Put the address of the next block inside each block.
        std::cout << "Bucket " << nextNullBucketIndex << ": ";
        for (int i = 0; i < _BUCKET_SIZE - 1; i++) {
            std::cout << static_cast<void*>(tempBlock) << ' ';
            new (tempBlock) char*(tempBlock += _ELEM_SIZE);
        }
        std::cout << static_cast<void*>(tempBlock) << std::endl;
        new (tempBlock) char*(nullptr); //The last block doesn't get an address, put nullptr in it.
    }

    char* tempAvailable = availableBlock;
    availableBlock = *reinterpret_cast<char**>(availableBlock);

    std::cout << "Returning: " << static_cast<void*>(tempAvailable) << std::endl;
    return static_cast<void*>(tempAvailable);
}

void Kennel::deallocate(void* loc) {
    new (loc) char*(availableBlock); //Store availableBlock's contained address in loc.
    availableBlock = static_cast<char*>(loc); //Set availableBlock's contained address to be loc's address.
}

每次运行程序时问题都不同。以下是有关尝试运行时遇到的更常见问题的一些信息。

在分配

时尝试执行Kennel.cpp第48行时经常会中断
std::cout << "Returning: " << static_cast<void*>(tempAvailable) << std::endl;

它经常在我的main函数中断行,删除Cat对象。

当程序调用Kennel的解构函数时,它有时会在程序结束时中断。

等等...

正如我所说,它似乎是随机的,它将决定打破哪一行代码。此外,我几乎可以肯定问题出在Kennel类中,因为我使用我的朋友的Kennel.h和Kennel.cpp来使用我的代码,它运行得很完美。

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:4)

buckets[nextNullBucketIndex] = new char(_BUCKET_SIZE * _ELEM_SIZE);

这只分配一个char,而不是它们的数组。然后,您继续将内容写入您不拥有的内存中。 <{1}} std::string同样的记忆,然后你的堆就搞砸了。