【问题标题】:Deallocating memory释放内存
【发布时间】:2011-05-10 14:22:20
【问题描述】:

对于一个项目,我必须实现一个 bitset 类。到目前为止,我的代码是:

头文件

#ifndef BITSET_H_
#define BITSET_H_
#include <string>
#include <cmath>

using namespace std;

// Container class to hold and manipulate bitsets
class Bitset {
public:
    Bitset();
    Bitset(const string);
    ~Bitset();

    // Returns the size of the bitset
    int size();

    // Sets a bitset equal to the specified value
    void operator= (const string);

    // Accesses a specific bit from the bitset
    bool operator[] (const int) const;

private:
    unsigned char *bitset;
    int set_size;
    // Sets a bitset equal to the specified value
    void assign(const string);
};
#endif /* BITSET_H_ */

源文件

#include "bitset.h"

Bitset::Bitset() {
    bitset = NULL;
}

Bitset::Bitset(const string value) {
    bitset = NULL;
    assign(value);
}

Bitset::~Bitset() {
    if (bitset != NULL) {
        delete[] bitset;
    }
}

int Bitset::size() {
    return set_size;
}

void Bitset::operator= (const string value) {
    assign(value);
}

bool Bitset::operator[] (const int index) const {
    int offset;

    if (index >= set_size) {
        return false;
    }

    offset = (int) index/sizeof(unsigned char);
    return (bitset[offset] >> (index - offset*sizeof(unsigned char))) & 1;
}

void Bitset::assign(const string value) {
    int i, offset;

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

    bitset = new unsigned char[(int) ceil(value.length()/sizeof(unsigned char))];

    for (i = 0; i < value.length(); i++) {
        offset = (int) i/sizeof(unsigned char);
        if (value[i] == '1') {
            bitset[offset] |= (1 << (i - offset*sizeof(unsigned char)));
        } else {
            bitset[offset] &= ~(1 << (i - offset*sizeof(unsigned char)));
        }
    }

    set_size = value.length();
}

我的问题是我在解构器和分配方法核心转储中的删除语句。不需要释放这个内存吗?从我目前所读到的内容来看,每当你调用 new 时,总是需要使用 delete 命令。

编辑:我已经更改了上面的代码以反映其中一项修复。我在构造函数中添加了 bitset = NULL。这修复了分配方法中的核心转储,但是我仍然在解构器中遇到错误。

【问题讨论】:

  • 旁注:sizeof(unsigned char) 始终是1,可能你想要的是std::numeric_limits&lt;unsigned char&gt;::digitsCHAR_BIT。两个整数相除也会产生另一个整数(截断任何分数)。
  • Brian 发现了一个严重错误。上面的某事找到了另一个。还要注意,您分配的字节数是必要的 8 倍: sizeof 以字节为单位,而不是位。 (如果您的系统有 并使用 int8_t,我认为如果您包含它会更容易阅读,否则您自己 typedef 它,那么您可以假设 sizeof == 1)。例如。 bitset = new int8_t[(value.size() + 7) / 8].
  • 谢谢你指出这一点。我没有意识到这一点。
  • 您接受了一个答案,但评论说它没有解决您的问题,“我的解构器中的删除语句仍然失败”。我的回答(一天后到目前为止为 0 票)可能解决了您的问题。仅供参考......干杯,
  • 此类使用资源(动态数组)尝试管理它。这是不好的。要么管理资源,要么使用资源。对于前者,您有 std::vector,因此您应该只使用 std::vector 作为您的资源。这大大解决了您的问题。 (显然你也会在实际代码中使用std::bitset。)

标签: c++ memory delete-operator


【解决方案1】:

我认为您应该在第二个构造函数中将 bitset 初始化为 NULL

为什么?

因为指针变量不一定会初始化为NULL。因此,当您使用第二个构造函数时,您可能会尝试delete[] 一些随机内存地址。

所以你应该有:

Bitset::Bitset(const string value) : bitset(NULL)
{
    assign(value);
}

【讨论】:

  • +1,bitset 在用于assign 之前没有显式初始化,所以它里面有一些垃圾地址。
  • 好电话。这修复了我在 assign 方法中得到的核心转储,但是我的解构器中的 delete 语句仍然失败。
  • @blcArmadillo,我有一个简单的main 函数,它只使用字符串构造函数创建了一个Bitset,并且使用Brian 的代码,核心转储消失了。
【解决方案2】:

您很可能在某处复制了Bitset。您尚未定义复制构造函数,而不是复制赋值运算符。复制的结果是你有两个实例,它们都认为他们应该在完成时释放动态分配的数组。

这被称为三法则:如果您定义了析构函数、复制构造函数或复制赋值运算符中的任何一个,那么您很可能需要定义所有三个 em>。

现在,关于您的代码:

#include "bitset.h"

好的。

Bitset::Bitset() {
    bitset = NULL;
}

(1) 您没有包含保证定义NULL 的标头。

(2) 您没有初始化成员 set_size,因此索引运算符中的检查可能/将使用具有未定义行为的不确定值。

(3) 通常更喜欢使用初始化列表而不是赋值(这可以避免例如先进行默认构造然后赋值)。

Bitset::Bitset(const string value) {
    bitset = NULL;
    assign(value);
}

(4) 通常,用赋值来表达构造并不是一个好主意。相反,用构造来表达分配。

Bitset::~Bitset() {
    if (bitset != NULL) {
        delete[] bitset;
    }
}

(5) 不需要检查NULL;你可以安全地delete 一个空指针。

int Bitset::size() {
    return set_size;
}

(6) 呃,好吧,set_size 是没有初始化的成员……另外,这个成员函数应该是 const

void Bitset::operator= (const string value) {
    assign(value);
}

(7) 赋值运算符通常应该返回对被赋值对象的引用。这只是一个约定,但这是您班级的用户所期望的。

(8) 通过值或引用const 传递一个in-argument。一般来说,对于内置类型,选择按值,对于其他类型,例如std::string,选择引用const。也就是说,形式参数最好是string const&amp; value

bool Bitset::operator[] (const int index) const {
    int offset;

    if (index >= set_size) {
        return false;
    }

    offset = (int) index/sizeof(unsigned char);
    return (bitset[offset] >> (index - offset*sizeof(unsigned char))) & 1;
}

(9) 首先是未初始化的set_size 成员。

(10) 然后,请注意sizeof(unsigned char) 根据定义为 1。您可能想在这里使用来自&lt;limits.h&gt;CHAR_BIT。或者只使用 8,除非您计划支持 Unisys 计算机(9 位字节)或德州仪器数字信号处理器(16 位字节)。

void Bitset::assign(const string value) {
    int i, offset;

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

(11) 不需要检查NULL

    bitset = new unsigned char[(int) ceil(value.length()/sizeof(unsigned char))];

(12) 如前所述,sizeof(char) 按定义为 1。

(13) 除法具有整数参数,因此是整数除法,而不是浮点除法。想必你想要的就是诀窍(a+b-1)/b

    for (i = 0; i < value.length(); i++) {

(14) 风格:声明一个变量尽可能接近它的第一次使用。这里的意思是直接在循环头声明循环计数器i,像这样:for( int i = 0, ...

        offset = (int) i/sizeof(unsigned char);

(14) offset 也是如此。但是对于这个变量,你不打算改变它的值,所以也要声明它const

        if (value[i] == '1') {
            bitset[offset] |= (1 << (i - offset*sizeof(unsigned char)));
        } else {
            bitset[offset] &= ~(1 << (i - offset*sizeof(unsigned char)));
        }

(15) 更好地重新考虑这些班次操作!

    }

    set_size = value.length();
}

干杯,

【讨论】:

    【解决方案3】:

    确保分配大小不为零,我怀疑这就是这里发生的事情,并且您只是在写入未分配的垃圾内存。在 valgrind 下运行也会发现这一点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-23
      • 2013-12-05
      • 2015-04-22
      • 2011-01-17
      • 2021-12-23
      • 2017-06-29
      • 2018-08-14
      相关资源
      最近更新 更多