2

私は C++ クラスの宿題に取り組んでいますが、いくつかの問題があります。item::operator= によって呼び出される item::name() の「サイズ 8 の初期化されていない値の使用」と「サイズ 8 の無効な読み取り」が原因で、私のプログラムはセグメンテーション違反を起こしています。

#ifndef ITEM_H
#define ITEM_H

const double WEIGHT_DEFAULT = 1.0;
const int ITEM_NAME_LENGTH = 30;

class item {
public:
    // Constructors and deconstructor
    item();
    item(char* nme, double weight);
    virtual ~item();

    // Copy constructor
    item(const item& itm);

    // Overload assignment operator
    const item& operator=(const item& itm);

    // Overload inequality operator
    bool operator!=(const item&) const;

    // Mutators and accessors
    const char* name(void) const;
    double weight(void) const;
    void weight(double wght);
    void name(char* nme);

protected:
private:
    char* m_name;
    double m_weight;
};

#endif // ITEM_H

問題があると思われる実装の部分を次に示します。

... 

const item& item::operator=(const item& itm)
{
    if (strcmp(this->name(), itm.name()) != 0)
    {

        this->weight(itm.weight());
        strcpy(m_name, itm.name());
    }

    return *this;
}

const char* item::name(void) const {
    return m_name;
}

...

ご覧のとおり、割り当ての一部は c-strings を使用することであるため、私は面倒な詳細で立ち往生しています。ポインターとクラスについての私の理解では、両方を使用する場合、デストラクタを実装し、コンストラクタをコピーし、代入演算子をオーバーロードする必要があります。上記のすべてを実行しました。Stack Overflow でコピー アンド スワップ イディオムに関する情報をいくつか見て、それを実装しようとしましたが、コードで動作させることもできませんでした。

私の脳は、どこが間違っていたのかを突き止めようとして混乱しています。誰かが私に欠けているものを教えてもらえますか?

ありがとう!


編集

コンストラクタ、デストラクタなどは次のとおりです。

item::item() {
    //ctor

    m_name = new char[ITEM_NAME_LENGTH];
    strncpy(m_name, " ", ITEM_NAME_LENGTH - 1);
    this->weight(WEIGHT_DEFAULT);

    return;
}

item::item(char* nme, double wght) {
    m_name = new char[ITEM_NAME_LENGTH];

    strncpy(m_name, nme, ITEM_NAME_LENGTH - 1);

    // We want to check for a rational value being
    // passed in to weight. In theory, an item has
    // to have *some* kind of weight, so we check
    // for a weight of 0. If a weight of 0 has been passed in,
    // we instead initialize the item's weight to the
    // default weight (set in the header file).
    if (wght > 0.0) {
        this->weight(wght);
    } else {
        this->weight(WEIGHT_DEFAULT);
    }

    return;
}

item::~item() {
    //dtor

    // TODO: We need to clean up any variables here.
    delete[] m_name;
}

item::item(const item& itm) {
    // copy ctor
    this->weight(itm.weight());
    strncpy(m_name, itm.name(), ITEM_NAME_LENGTH - 1);

}

const item& item::operator=(const item& itm)
{
    if (strcmp(this->name(), itm.name()) != 0)
    {

        this->weight(itm.weight());
        strcpy(m_name, itm.name());
    }

    return *this;
}

bool item::operator!=(const item& itm) const
{
    return (strcmp(m_name, itm.name()) != 0);
}

編集2

名前 c-string を動的に割り当てようとするのをやめたので、重み関数でメモリ エラーが発生しています...

double item::weight(void) const {
    return m_weight;
}

void item::weight(double wght)
{
    m_weight = wght;
}
4

2 に答える 2

1

まず、ステートメントreturn;から明示的にする必要はありません。void

2番目:コピーコンストラクターを作成するときは、通常のコンストラクターの場合と同じように、そのコンストラクターのメモリを保持するために使用されるスペースを割り当てる必要があります。

コピーコンストラクタでこれを試してください。

m_name = new char[ITEM_NAME_LENGTH];

編集:完全を期すために、これは私の「機能しているように見える」コードです。

#include <stdio.h>
#include <string.h>


const double WEIGHT_DEFAULT = 1.0;
const int ITEM_NAME_LENGTH = 30;

class item {
public:
    // Constructors and deconstructor
    item();
    item(char* nme, double weight);
    virtual ~item();

    // Copy constructor
    item(const item& itm);

    // Overload assignment operator
    const item& operator=(const item& itm);

    // Overload inequality operator
    bool operator!=(const item&) const;

    // Mutators and accessors
    const char* name(void) const;
    double weight(void) const;
    void weight(double wght);
    void name(char* nme);

protected:
private:
    char* m_name;
    double m_weight;
};


const item& item::operator=(const item& itm)
{
    if (strcmp(this->name(), itm.name()) != 0)
    {

        m_name = new char[ITEM_NAME_LENGTH];
        this->weight(itm.weight());
        strcpy(m_name, itm.name());
    }

    return *this;
}

const char* item::name(void) const {
    return m_name;
}

double item::weight(void) const {
    return m_weight;
}

void item::weight(double wght) {
    m_weight = wght;
}

item::item() {
    //ctor

    m_name = new char[ITEM_NAME_LENGTH];
    strncpy(m_name, " ", ITEM_NAME_LENGTH - 1);
    this->weight(WEIGHT_DEFAULT);

    return;
}

item::item(char* nme, double wght) {
    m_name = new char[ITEM_NAME_LENGTH];

    strncpy(m_name, nme, ITEM_NAME_LENGTH - 1);

    // We want to check for a rational value being
    // passed in to weight. In theory, an item has
    // to have *some* kind of weight, so we check
    // for a weight of 0. If a weight of 0 has been passed in,
    // we instead initialize the item's weight to the
    // default weight (set in the header file).
    if (wght > 0.0) {
        this->weight(wght);
    } else {
        this->weight(WEIGHT_DEFAULT);
    }

    return;
}

item::~item() {
    //dtor

    // TODO: We need to clean up any variables here.
    delete[] m_name;
}

item::item(const item& itm) {
    // copy ctor
    this->weight(itm.weight());
    m_name = new char[ITEM_NAME_LENGTH];
    strncpy(m_name, itm.name(), ITEM_NAME_LENGTH - 1);

}

bool item::operator!=(const item& itm) const
{
    return (strcmp(m_name, itm.name()) != 0);
}


int main(int argc, char* argv[])
{
    item i("test",2.0);
    item b = i;
    item c;
    item d = c;
    return 0;
}
于 2013-01-23T05:22:45.617 に答える
1

std::string の使用は演習の一部として出ていると思いますよね?それ以外の場合は、文字列処理の方法です。もう 1 つの方法は、文字列の動的割り当てを回避することです。代わりに、を使用してchar m_name[ITEM_NAME_LENGTH];ください。ところで:それはどの長さですか?名前の最大文字数の場合は+1、終端の NUL に が必要です。

とはいえ、もう 1 つ: 代入演算子では、 を比較if(this != &other)します。つまり、2 つのオブジェクトのアドレスを比較します。ポイントは、エラーが発生しやすい自己割り当てを避けることです。あなたの割り当ては、名前が異なるかどうかをチェックし、名前と重みをコピーするだけです。重さだけ違うとしたら?

于 2013-01-23T06:23:41.093 に答える