質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

1584閲覧

C++ 関数の中のアドレス記憶期間について

saito.kaz

総合スコア76

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2016/01/20 03:14

###前提・実現したいこと
下記のコードの中で、関数内で Worker* inputdata();でアドレスを返却し、w2にポインタを返しているのですが、関数内でアドレスが解放されているのにも関わらず、w1.ShowDataPointer(w2);がなぜか動いています。
これはコンパイラの影響でしょうか。ちなみにPaiza.ioを利用しています。

###ソースコード

<ヘッダー文> class Worker{ public: static int no; int num; static char* CompanyName; double salary; char department[100]; char name[100]; Worker(); ~Worker(); Worker(double salary ,char department[100], char name[100]); void ShowData(); void ShowDataPointer(Worker *a); Worker* inputdata(); }; <メイン文> #include <iostream> using namespace std; #include <iostream> #include "string.h" #include "Worker.h" using namespace std; int Worker::no = 0; char* Worker::CompanyName = "ABC"; Worker::Worker(){ this->num = no; this->salary = 0; strcpy(this->department, "NotDefinedDepartment"); strcpy(this->name, "NotDefinedName"); no++; } Worker::~Worker(){ } Worker::Worker(double salary, char department[100], char name[100]){ this->num = no; this->salary = salary; strcpy(this->department,department); strcpy(this->name,name); no++; } void Worker::ShowData(){ cout << "no = " << this->num << "\n"; cout << "salary = " << this->salary << "\n"; cout << "department = " << this->department << "\n"; cout << "name = " << this->name << "\n"; } void Worker::ShowDataPointer(Worker *a){ cout << "no = " << a->num << "\n"; cout << "salary = " << a->salary << "\n"; cout << "department = " << a->department << "\n"; } Worker* Worker::inputdata(){ Worker obj; obj.num = no; obj.salary=100; strcpy(obj.department, "inputdata"); strcpy(obj.name, "name_inputdata"); no++; cout << "this is inputdata" << "\n"; obj.ShowData(); cout << "this is end of inputdata" << "\n"; // return &obj; 関数を抜けるとき、アドレスが解法されるので下記のように行う必要がある。 return &obj; } int main(void){ Worker w[3]; Worker w1; Worker* w2; Worker* someone[3]; for(int i=0 ; i<3 ;i++){ w[i].salary = 100; strcpy(w[i].department, "E"); strcpy(w[i].name, "Takayuki"); someone[i] = &w[i]; cout << "salary = " << someone[i]->salary << "\n"; } w2 = w1.inputdata(); //w1は関数を抜けたとき、削除される。 cout << "w1 ===== " << &w1 << "\n"; cout << "---------w1.ShowDataPointer();------------" << "\n"; w1.ShowDataPointer(w2); cout << "---------w2.ShowData();------------" << "\n"; w2->ShowData(); cout << "---------------------" << "\n"; w1.ShowData(); w[0].ShowData(); cout << "---------------------" << "\n"; w[1].ShowData(); cout << "---------------------" << "\n"; w[0].ShowDataPointer(&w[0]); }

###補足情報(言語/FW/ツール等のバージョンなど)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

たまたまです。
おそらく、関数から出た後、そのデータを使用するまでに、同じアドレスが他の用途で
使われていないのでしょう。
obj自体を返したらどうですか?

投稿2016/01/20 03:21

nob.

総合スコア711

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Chironian

2016/01/20 05:47

私もobjへのポインタではなくobj自体を返すことに一票入れます。 関数側で獲得したメモリを呼び出し元へ返却することってC++にとっての頭の痛い問題です。 obj自体を返却するとコピーされそうですが、最近のコンパイラは原則としてコピーせずに移動してくれるらしいです。 ↓C++11ではそのように規定されたとか。 http://d.hatena.ne.jp/joynote/20110822/1314012953
saito.kaz

2016/01/21 01:25

新しい情報ありがとうございます。 参考になります。
guest

0

nob.さんが書かれているように、たまたま解放後もまだ使用されていなかったため「動いてしまった」と考えてください。
加えて、このinputdata()関数は危険な関数であることを理解しておく必要があると思います。今回のように「たまたま」動作することもありますが、リリースしたあとで原因不明の不正終了に悩まされる可能性があります。

オブジェクトのポインタを返す関数を作るのであれば、呼び出し側で利用している間はそのポインタが指すオブジェクトが生存し続けることを保証するような作りにするべきです。

C++

1Worker* Worker::inputdata() { 2 Worker* obj = new Worker(); 3 obj->num = no; 4 obj->salary = 100; 5 strcpy(obj->department, "inputdata"); 6 strcpy(obj->name, "name_inputdata"); 7 no++; 8 cout << "this is inputdata" << "\n"; 9 obj->ShowData(); 10 cout << "this is end of inputdata" << "\n"; 11 return obj; 12} 13 14int main(void) { 15 Worker w1; 16 Worker* w2; 17 // (略) 18 : 19 : 20 w2 = w1.inputdata(); 21 : 22 : 23 delete w2; // ここで開放 24}

投稿2016/01/20 04:44

KoichiSugiyama

総合スコア3041

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

saito.kaz

2016/01/21 01:25

とても勉強になります。 ありがとうございます。
guest

0

アドレスを開放してもデータが削除されるわけではありません。
アドレスが解放されるとOSに対して別の用途に使っていいメモリ領域として通知されるので
OSにメモリ使用のリクエストが渡されたときに別用途で使われる可能性があります。

今回はアドレス開放してすぐ参照しているので
データがそのまま残っていて問題なく参照できていますが
たとえば以下のコードのようにしたときに
w[0]->ShowData();は最初に作ったデータではなく
もっとずっと後に作ったデータになったりします。

C++

1Worker *w[10000]; 2for(int i = 0; i < 10000; i++){ 3 w[i] = w1.inputdata(); 4} 5w[0]->ShowData();

※メモリの再利用がされたときにメモリに乗るデータがWorkerクラスのデータでなかったり
Workerクラスのデータでもデータの開始アドレスがずれると全く意味不明のデータになったりします。

投稿2016/01/20 04:41

kutsulog

総合スコア985

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

saito.kaz

2016/01/21 01:25

ありがとうございます。 参考になります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問