1

ダクトを通る境界層の流れの特性を計算しています。ダクトのジオメトリを格納するクラスCChannel、流体のグローバルプロパティを保持するCFlow、および境界層のローカルパラメータを格納するCNodeがあります。現在の形式でプログラムを実行すると、CChannel内のGridPointsベクトルの最初の要素(変数「alpha」)に、CFlowクラスのプライベートメンバーであるUinfと同じメモリ位置が割り当てられます。後者のクラスを変更して、それが保持するフィールドがポインターではなく通常の変数になるようにすると、問題は解消されます。また、クラスコンストラクター内のGridPointsベクトル用にメモリスペースを予約しようとしましたが、効果はありませんでした。答えを探していたときに、これは組み込みのコードオプティマイザーが原因である可能性があることがわかりましたが、他に何も学ぶことができませんでした。(もしそうなら、どうすれば効率を落とさずにこれを回避できますか?)2つの異なるメモリ割り当てモード(ヒープとスタック)の違いが原因で問題が発生すると推測しています。グローバルフローパラメータをポインタとして保存し、将来この問題を回避できるように、なぜこれが正確に発生しているのかを知りたいと思います。

Program.cpp

#include <iostream>

#include "Channel.h"    // stores the channel geometry
#include "Flow.h"   // stores the fluid properties and free stream data
#include "Node.h"       // holds the local BL flow properties, e.g. BL thickness, lambda, etc.

using namespace std;

int main(void)
{
    int NoNodes=21;
    CChannel MyChan(4, 1.2, .8);    // L, h1, h2
    MyChan.MeshUniform(NoNodes);

    CFlow Flow1(.5,1.529e-5,1.19);  // Uinf, niu, ro

    for (int i=0;i<NoNodes;i++)
    {
        MyChan.GridPoints->at(i).GetAlpha();
    }
    return(0);
}

Node.h

#pragma once
class CNode
{
public:
    double *alpha, *x, *lambda; // properties dependent on the Pollhausen velocity profile

    CNode(void);
    ~CNode(void);

    void GetAlpha(void);    // calculates alpha

};

Node.cpp

#include "Node.h"
#include <iostream>

CNode::CNode(void)
{
    alpha=new double;

    lambda=new double;
    *lambda=0;
}

CNode::~CNode(void)
{
    delete alpha, x, lambda;
}

void CNode::GetAlpha(void)
{
    *alpha=(.3-*lambda/120.);
}

Flow.h

#pragma once
class CFlow
{
private:
    double *Uinf, *niu, *ro;
public:
    CFlow(double, double, double);
    ~CFlow(void);
};

Flow.cpp

#include "Flow.h"

CFlow::CFlow(double u, double visc, double den)
{
    Uinf=new double;
    niu=new double;
    ro=new double;
    *Uinf=u;    // free stream velocity (assumes the inflow is parallel to the channel's CL) [m/s]
    *niu=visc;  // kinematic viscosity of the fluid [m^2/s]
    *ro=den;    // density of the fluid [kg/m^3]
}


CFlow::~CFlow(void)
{}

Channel.h

#pragma once
#include <vector>

#include "Node.h"

class CChannel
{
public:
    double *L, *h1, *h2;    // h1 & h2 defined from the CL => make use of the problem assumed to be symmetric
    std::vector<CNode> *GridPoints; // stores data for each individual grid point

    CChannel(double, double, double);
    ~CChannel(void);

    void MeshUniform(int);  // creates a uniform distribution of nodes along the length of the channel
};

Channel.cpp

#include "Channel.h"

CChannel::CChannel(double length,double height1,double height2)
{
    L=new double;   // allocate memory
    h1=new double;
    h2=new double;
    GridPoints = new std::vector<CNode>;

    *L=length;      // assign input values
    *h1=height1;
    *h2=height2;
}


CChannel::~CChannel(void)
{
    delete L, h1, h2, GridPoints; // delete all the members of the class
}


void CChannel::MeshUniform(int NoNodes)
{
    GridPoints->resize(NoNodes);    // resize the vector
    double dx=*L/(NoNodes-1);   // increment of length between each pair of nodes
    for (int i=0; i<NoNodes; i++)
        *GridPoints->at(i).x=0.+i*dx;   // assign the location to each node
}
4

2 に答える 2

1

コンパイルされていますが、説明は、ポインターコードでコピー可能なオブジェクトを記述していないことです (Piotr が言うように、3 のルールに従っていません)。このバグが原因で、メモリの割り当てが開始され、メモリが解放されてから再度割り当てられます。偶然にも、メモリを再度割り当てる、解放されたばかりの同じアドレスが再利用されます。そのため、同じポインター値が表示されます。

MyChan.GridPoints->at(0).alphaはポインタですが、それが指しているメモリは解放されています。次に、さらにメモリを割り当てると、指してFlow1.Uinfいる同じ解放されたメモリが再利用されます。MyChan.GridPoints->at(0).alphaしたがって、両方のポインターに対して同じ値が得られます。

あなたが持っているもう一つの誤解

delete L, h1, h2, GridPoints; // delete all the members of the class

クラスのすべてのメンバーを削除するわけではありません。それだけ

delete L; // delete all the members of the class
delete h1;
delete h2;
delete GridPoints;

それをします。あなたが書いたものはGridPointsのみを削除します。理由の説明については、C++ のコンマ演算子を調べてください。

于 2012-10-27T19:52:56.253 に答える
1

すでに説明したように、これらすべてのポインターは必要ありません。それらを生の変数に変更してください。

いつかポインタが必要な状況になったら、Rule of Three を思い出してください。Rule of Threeとは何ですか? .

この特定のクラスのように、クラスでコピー コンストラクターと代入演算子を定義しないことで、この規則を破りました。

class CNode
{
public:
    double *alpha, *lambda; // properties dependent on the Pollhausen velocity profile

    CNode(void);
    ~CNode(void);

    void GetAlpha(void);    // calculates alpha

};

CNodeこれを使用しているため、このオブジェクトstd::vector<CNode>の間違ったコピーに苦しんでいます。CNode

したがって、コピー コンストラクターと代入演算子を追加する必要があります。この単純なクラスの例のように、ポインターをまだ使用している場合でも、問題は解消されます。

class Example {
public:
  Example() : p(new int()) {}
  ~Example() { delete p; }
  Example(const Example& e) p(new int(e.p?*e.p:0)) {}
  Example& operator = (Example e)
  {
      std::swap(e.p, p);
      return *this;
  }
private:
  int* p;  
};
于 2012-10-27T19:48:51.747 に答える