0

私のクラスNRRanNormalは正規分布確率変数を表しています。デフォルトでは、インスタンスは平均 0 および stdev 1 (つまり、標準の正規確率変数) で正規分布されます。

オブジェクトをコピーNRRanNormalすると、コピーされた (またはコピー コンストラクターを介して構築された) オブジェクトの平均値と標準偏差が文字化けしてナンセンスになることがありますこの文字化けの原因を見つけるのに苦労しています。

テスト目的で、次の関数は特定のNRRanNormalオブジェクトの平均値と標準偏差を表示します。

void go(NRRanNormal& rv, const string label) {
    std::cout << label     << "\n"
              << "Mean:  " << rv.getMean()  << "\n"
              << "Stdev: " << rv.getStdev() << "\n\n";
}

それでは、次の 4 つのケースで何が起こるか見てみましょう。

NRRanNormal foo;
go(foo, "foo");

NRRanNormal bar1 = foo;
go(bar1, "bar1");

NRRanNormal bar2;
bar2 = foo;
go(bar2, "bar2");

NRRanNormal bar3(foo);
go(bar3, "bar3");

上記のステートメントの出力は次のとおりです。

foo
Mean:  0
Stdev: 1

bar1
Mean:  5.55633e-317
Stdev: 6.95332e-310

bar2
Mean:  0
Stdev: 1

bar3
Mean:  0
Stdev: 0

ご覧のとおり、オブジェクト ( foo) をインスタンス化するだけで、期待どおりに機能します。

今、私がするときNRRanNormal bar1 = foo;、オブジェクトbar1は文字化けしています。しかし、私が行うNRRanNormal bar2; bar2 = foo;と、オブジェクトbar2は文字化けしません。これは私を困惑させます。のようなステートメントブロックだと思いました

MyClass A;
MyClass B = A;

コンパイラによって実際にステートメントブロックに変換されます

MyClass A;
MyClass B;
B = A;

したがって、すぐ上に書いたことが間違っていない限り、bar1とはまったく同じメンバー値bar2を持つ必要があるようです。しかし、上に貼り付けた出力からわかるように、文字化けしていますが、問題ありません。 bar1bar2

どうすればいいの?

bar3文字化けしていることにも気付くでしょう。これが同じ問題なのか、別の問題なのかわかりません。


のインターフェースと実装の簡略化されたバージョンを次に示しますNRRanNormal

class NRRanNormal {
public:

    NRRanNormal();

    ~NRRanNormal();

    NRRanNormal(const NRRanNormal& nrran);

    NRRanNormal& operator= (const NRRanNormal& nrran);

    double getMean()  const;    
    double getStdev() const;    
    long   getSeed()  const;

private:    
    double m_mean, m_stdev;     
    long m_seed;    
    Normaldev* stream; // underlying C struct RN generator

};

NRRanNormal::NRRanNormal() { // by default, N(0,1)
    m_mean  = 0.0;
    m_stdev = 1.0;
    m_seed  = 12345L;
    stream  = new Normaldev(m_mean, m_stdev, m_seed);
}

NRRanNormal::~NRRanNormal() { delete stream; }

NRRanNormal::NRRanNormal(const NRRanNormal& nrran) {
    stream = new Normaldev(nrran.getMean(),nrran.getStdev(),nrran.getSeed());
    *stream = *(nrran.stream);
}

NRRanNormal& NRRanNormal::operator= (const NRRanNormal& nrran) {            
    if(this == &nrran)
        return *this;

    delete stream;
    stream = new Normaldev(nrran.getMean(),nrran.getStdev(),nrran.getSeed());
    *stream = *(nrran.stream);

    return *this;
}

double NRRanNormal::getMean()  const { return m_mean; }    
double NRRanNormal::getStdev() const { return m_stdev; }    
long   NRRanNormal::getSeed()  const { return m_seed; }

Normaldev構造体は Numerical Recipes 3d Edition からのものです。

コピー代入演算子またはコピー コンストラクターに何か問題がありますか?


これはNormaldev、独自の計算を取り除いたものです。

typedef double Doub;        
typedef unsigned long long int Ullong;
typedef unsigned int Uint;

struct Ranq1 {
    Ullong v;
    Ranq1(Ullong j) : v(/* some long number here */) {
        /* proprietary calculations here */
    }
    inline Ullong int64() {
        /* proprietary calculations here */
    }
    inline Doub doub() { /* proprietary calculations here */ }
    inline Uint int32() { return (Uint)int64(); }
};

struct Normaldev : Ranq1 {
    Doub mu,sig;
    Normaldev(Doub mmu, Doub ssig, Ullong i):
    Ranq1(i), mu(mmu), sig(ssig){}
    Doub dev() {
        /* proprietary calculations here */
    }
};
4

1 に答える 1

4

これはあなたの問題です

NRRanNormal::NRRanNormal(const NRRanNormal& nrran) {
    stream = new Normaldev(nrran.getMean(),nrran.getStdev(),nrran.getSeed());
    *stream = *(nrran.stream);
}

する必要があります

NRRanNormal::NRRanNormal(const NRRanNormal& nrran) : 
    m_mean(nrran.m_mean), 
    m_stdev(nrran.m_stdev), 
    m_seed(nrran.m_seed)
{
    stream = new Normaldev(nrran.getMean(),nrran.getStdev(),nrran.getSeed());
    *stream = *(nrran.stream);
}

コピー コンストラクターは、平均、stddev、およびシードのコピーに失敗します。代入演算子には、本来あるべき同じ問題があります

NRRanNormal& NRRanNormal::operator= (const NRRanNormal& nrran) {            
    if(this == &nrran)
        return *this;

    m_mean  = nrran.m_mean;
    m_stdev = nrran.m_stdev;
    m_seed  = nrran.m_seed;
    delete stream;
    stream = new Normaldev(nrran.getMean(),nrran.getStdev(),nrran.getSeed());
    *stream = *(nrran.stream);

    return *this;
}

クラスのトリッキーなポインターに集中しすぎて、基本的なことを忘れていたと思います。

ところでコード

MyClass A;
MyClass B = A;

コンパイラによって実際に変換されます

MyClass A;
MyClass B(A);

つまりMyClass B = A;、コピー コンストラクターを呼び出します (A と B が同じ型であると仮定します)。

于 2013-09-27T05:46:13.063 に答える