2017-03-23 23 views
0

私はランダムなモンスタージェネレータを作成し、次にモンスターのパラメータを印刷する必要があるコースのプログラムを作成しています。関数間で文字列を転送するC++

私が生成し、データを印刷するmainで、このループを使用します。

for (g=0; g < m; g++) 
    { 
     tab[g] = &createRandomMonster(g); 
     printMonsterData(*tab[g]); 
    } 

この関数モンスター生成するために:印刷用

Monster createRandomMonster(int g) 
{ 
    ostringstream buffer; 
    buffer << ++g; 
    string name = buffer.str(); 
    Monster nowypotwor{ name, MonsterType(rand() % 6 + 1), rand() % 25 + 5, (double)(10.0 + (rand()/(double)(RAND_MAX))*(30.0 - 10.0)) }; 
    return nowypotwor; 
} 

そして、この機能を:

void printMonsterData(const Monster &potwor) 
{ 
    cout << "potwor: " << potwor.name << endl << "typ: " << getTypeName(MonsterType(potwor.type)) << endl << "atak: " << potwor.attack << endl << "zycie: " << potwor.health << endl << endl; 
} 

私はモンスターの名前を印刷しません。 printMonsterDatacreateRandomMonsterにある場合は行いますが、それは私が行う必要があるmainで行います。

+6

rvalueのアドレスを取っています。この場合は、一時的に 'createRandomMonster'関数から返されます。 'Monster'がすでに破壊されているため、後でアクセスするときに未定義の動作が起こります! –

+0

文字列をどのように保護する必要がありますか?生成された数値はすべて正しく転送されますが、それは問題の文字列です。 –

+3

いいえ、そうではありません。あなたのモンスターは '&createRandomMonster(g);'行の後に破壊され、もはや有効ではないメモリにアクセスします。しかし古いデータのいくつかはまだそこにあり、あなたはそれらを "エコー"として見ることができます。 ps。ポーランド語と英語のミキシングは、悪いスタイルと見なすことができます。 – Logman

答えて

0

モンスターのリターンをキャプチャする必要があります。すなわち、 モンスターaMonster = createRandomMonster(g); タブ[g] = & aMonsterと言うことができます。

EDITでも、このソリューションではタブ[g]はforループの寿命、つまりaMonsterの寿命の間のみ有効です。これは参照による操作の別の結果です。あなたがメインの最も外側のスコープにモンスターを宣言し、それに戻るならば、この制限を回避することができます...

タブがモンスター配列ではなくモンスター*配列である理由はありますか?

tab[g] = &createRandomMonster(g); 

createRandomMonster戻りMonsterクラス:それは

+0

ユーザーが指定する配列サイズが必要です。 –

+0

静的配列の制限は、その内容に基づいて変更されません。静的な(ローカルに宣言された、スタックに割り当てられた)配列の配列でも、ポインタの配列でも、コンパイル時の量を知る必要があります。配列が動的に割り当てられている場合、Monster *のいずれかと同じランタイム量のMonsterの配列を作成できます。 – schulmaster

0

これは間違っているあなたはすぐにそれを参照して印刷するためにそれを渡すために欽慕特に以来...私は何かが欠けていない限り、後者のように、より理にかなってそれは返されるものは、完全なステートメントの終わりの直後に破棄される一時的なオブジェクトです(セミコロンの後ろには、セミコロン;の文字です)。したがって、この一時的なオブジェクトのアドレスを&で取得すると、実際にはすぐに破棄される一時的なアドレスが取得され、tab[g]に未定義のビヘイビアが発生します。

私はあなたがtabにポインタとしてごMonsterオブジェクトを格納いけないが、その値によって示唆している:

std::vector<Monster> g; 

あなたはポインタは、その後、それらを保存する必要がある場合:

std::vector<std::unique_ptr<Monster>> g; 

とにcreateRandomMonsterを変更します。

std::unique_ptr<Monster> createRandomMonster(int g) 
{ 
    ostringstream buffer; 
    buffer << ++g; 
    string name = buffer.str(); 
    std::unique_ptr<Monster> nowypotwor = std::make_unique<Monster>(name, MonsterType(rand() % 6 + 1), rand() % 25 + 5, (double)(10.0 + (rand()/(double)(RAND_MAX))*(30.0 - 10.0))); 
    return nowypotwor; 
} 

および

tab[g] = createRandomMonster(g); 
0

あなたは関数がスマートポインタ(例えばを保持するために、「タブ」に変更、いっそのモンスター(モンスター*)へのポインタを返す、またはcreateRandomMonsterにする必要があります。 shared_ptr)を通常のポインタの代わりに使用し、その関数からそのポインタを返します。

std::vector<std::shared_ptr<Monster>> tab; 

std::shared_ptr<Monster> createRandomMonster(int g) 
{ 
    ostringstream buffer; 
    buffer << ++g; 
    string name = buffer.str(); 

    return std::make_shared<Monster>(name, 
     MonsterType(rand() % 6 + 1), rand() % 25 + 5, 
     (double)(10.0 + (rand()/(double)(RAND_MAX))*(30.0 - 10.0))); 
} 

for (g=0; g < m; g++) 
{ 
    tab[g] = createRandomMonster(g); 
    printMonsterData(*tab[g]); 
} 

あなたは多型の挙動を持つ必要がない場合は、それはベクトルの値を保持し、タブに右辺値をコピーするのが最善です:

std::vector<Monster> tab; 

for (g=0; g < m; g++) 
{ 
    tab[g] = createRandomMonster(g); 
    printMonsterData(tab[g]); 
} 
0

は、関数に文字列を転送するには、のいずれかに従うことができます

1)Cスタイル - 配列(静的/グローバル/ローカル)を宣言し、そのアドレス(またはC++のような参照)をポインタとして呼び出された関数に渡します。動的に割り当てられている場合は、代わりにポインタを渡します

2)C++スタイル - std :: stringを使用して、必要に応じてすべての拡張を実行します。これは、境界線を書き留めることを心配する必要はなく、あなたが関数から復帰したとき、または等価性を後で実行するときの魔法

関連する問題