0

この質問は以前に回答された可能性がありますが、2日間検索した後、解決策を見つけることができませんでした。

以下を格納するスタッククラスを作成しました__data

class __data
{
private:
    void* __p;
    __datatype __type;

public:
    __data(void);
    __data(int i);
    __data(double d);
    __data(char* s);
    __data(void (*f)(Stack));

    bool IsFunction(void);
    bool IsInteger(void);
    bool IsNumber(void);
    bool IsString(void);

    void* Get(void);
};

このクラスを作成したのは、スタックが文字列、関数(関数へのポインター)、double、および整数を格納できるようになるためです。

問題は、整数または倍精度浮動小数点数をスタックにプッシュしてからポップし、データへのポインターを取得する場合です(void* Get(void))値を出力してデバッグしているため、基本的に次のようになります。

void print(Stack s)
{
    __data d = s.Pop();

    if (d.IsNumber()) // BUG: never the number I pass to __data
        std::cout << "IsNumber - " << *((double*)d.Get()) << std::endl;
    else if (d.IsInteger()) // BUG: it always prints out 1
        std::cout << "IsInteger - " << *((int*)d.Get()) << std::endl; // 
    else if (d.IsString())
        std::cout << "IsString - " << (char*)d.Get() << std::endl;
    else if (d.IsFunction())
    {
        std::cout << "IsFunction - " << d.Get() << std::endl;
        ((void (*)(Stack))d.Get())(s); // calls the function
    }
}

何が間違っているのかわかりません。おそらくそれが私が割り当てる方法__p(によって返されるポインタGet())です。これらは__dataintegerとdoubleのコンストラクタです。

__data::__data(int i)
{
    __type = _dt_integer;
    __p = &i;
}
__data::__data(double d)
{
    __type = _dt_number;
    __p = &d;
}

したがって、基本的に私の問題は、返された整数またはdoubleを取得しようとすると、 (integer)または(double)void*の値が返されることです。12.13171e-314

お時間をいただきありがとうございます。これに対する答えがすでにある場合は申し訳ありません。

編集:

Stackクラスを書き直して、代わりに共用体を使用します。これが私の目標を達成するための最良の方法のようです。

4

5 に答える 5

1
__data::__data(int i)
{
    __type = _dt_integer;
    __p = &i; // this only stores the address of i on the stack
}

必要なのは

__data::__data(int* i) // have the caller pass the address of their i
{
    __type = _dt_integer;
    __p = i; // this stores what you need
}
于 2012-07-16T12:59:36.577 に答える
1

問題は、一時オブジェクトのアドレスを保存することです。例:この例では、一時的なのアドレスを保存しますdouble d

__data::__data(double d)
{
    __type = _dt_number;
    __p = &d;
}

オブジェクトは現在のスコープ(関数)にのみ存在し、スタック内の他の何かによってオーバーライドされる可能性があるため、アドレスは後で役に立たなくなります。

私が提案する解決策は、動的に割り当てられたコピーを作成することです。

__data::__data(double d)
{
    __type = _dt_number;
    __p = new double(d);
}

これによりオブジェクトが作成され、ポインタを手動で解放するまで存続しますdelete。のデストラクタでどちらを実行する必要がありますか__data

__data::~__data()
{
    delete __p;
}

更新:char *文字列型として使用するのではなく、C++と同等のものを使用することを強くお勧めしますstd::string。また、ライブラリを見ることができますboost::any。これは、基本的に達成したいことと同じことを行いますが、代わりにテンプレートを使用します。

于 2012-07-16T13:01:10.227 に答える
1
__data::__data(int i) 
{
    __type = _dt_integer;
    __p = &i; 
}
__data::__data(double d) 
{
    __type = _dt_number;
    __p = &d; 
}

ローカル変数へのポインタを取得するため

于 2012-07-16T13:02:29.380 に答える
1
__data::__data(int i)
{
    __type = _dt_integer;
    __p = &i;
}

あなたはそれをすることはできません!関数が戻った後は変数iが存在しないため、変数へのポインターにはガベージが含まれます。の値は、アドレスではなくi__dataクラスに保存する必要があります。(少なくとも)2つの方法があります。ポリモーフィズムを使用する(__dataデータ型ごとにのサブクラスを定義する)か、__dataサポートするデータ型ごとのメンバーを含む共用体を内部で宣言します。

于 2012-07-16T13:04:29.327 に答える
0

変数iとdは、関数__data(int i)、__ data(double d)の存続期間中のみ有効です。つまり、これらの変数は現在のスタックに作成され、関数を終了するときに削除されるため、プログラムの実行中は無効になる変数へのポインターを格納します。Get関数を呼び出すときは、「デッド」変数を指すポインターにアクセスします。

これらのメンバーをクラスに追加する必要があります。

class __data
{
private:
  int iInt;
  double dDouble;
}

関数を変更します...アドレスではなく値を保存します...

__data::__data(int i)
{
    __type = _dt_integer;
    iInt = i;
}
__data::__data(double d)
{
    __type = _dt_number;
    dDouble = d;
}

Get関数を変更することを忘れないでください。

void* __data::Get()
{
  switch( __type )
  {
    case _dt_integer:
      return (void*)iInt;
      break;
    case _dt_number:
      return (void*)dDouble;
      break;
  }

  return (void*)0;
}

その後、以下のように使用できます。

cout << "Int value " << (int)d.Get();
cout << "double value " << (double)d.Get();

それはあなたがやりたいことをする方法ですが、唯一のものです!ユニオンメンバーを使用して値を格納し、メモリ使用量を節約できます。

于 2012-07-16T13:08:58.693 に答える