nullptrチェックについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら

トピックに返信する


答えを正確にご入力ください。答えられるかどうかでスパムボットか否かを判定します。

BBCode: ON
[img]: ON
[flash]: OFF
[url]: ON
スマイリー: OFF

トピックのレビュー
   

展開ビュー トピックのレビュー: nullptrチェックについて

Re: nullptrチェックについて

#10

by Dixq (管理人) » 2年前

一応誤解のないように補足すると、shared_ptrはnewしたオブジェクトをdeleteする必要のないスマートポインタの一つでnull確認しなくていい質問の回答としては密接に関係あるものではないです。
JAVAやC#などのガベージコレクションのような使い方をC++で可能にするための仕組みです。
私が言いたかったのはタスクやオブジェクトのポインタリストを持って置き、そのリストをループする際にupdateやdrawすることでnull確認の必要がなくなりますということです。
参考まで

Re: nullptrチェックについて

#9

by dowhile » 2年前

皆さんご回答ありがとうございます。

shared_ptr、NullObjectパターン等、参考にさせていただきます。

Re: nullptrチェックについて

#8

by かずま » 2年前

dowhile さんが書きました: 書き直させて頂きます。

コード:

class FooA
{
public:

	BOOL Func() { return TRUE; }
};

class FooB
{
public:

	FooA* m_A;

	void Update()
	{
		for (;;) {
			if (m_A) {
				if (m_A->Func()) break;
			}
			m_A = new FooA();
		}
	}
};

int main()
{
	FooB fb;
	fb.Update();
}
これでどうですかね?
次のようにすると、FooB::m_A は nullptr に初期化されます。

コード:

int main()
{
    FooB *fbp = new FooB();
    fbp->Update();

    delete fbp;
}
new FooB はダメです。new FooB() です。

参考例

コード:

#include <iostream>

class FooA {
public:
    bool Func() { return true; }
};
 
class FooB {
public:
    FooA* m_A;
    int a[2];
 
    void Update() {
        for (int i = 0 ; i < 5; i++) {
            std::cout << "a[0]=" << a[0] << ", a[1]=" << a[1]
                << ", m_A=" << m_A << "\n";
            if (m_A) {
                if (m_A->Func()) break;
            }
            m_A = new FooA();
        }
    }
};
 
int main()
{
    FooB fb;
    fb.Update();
    putchar('\n');

    FooB *fbp1 = new FooB;
    fbp1->Update();
    putchar('\n');

    FooB *fbp2 = new FooB();
    fbp2->Update();

    delete fbp1;
    delete fbp2;
}
VC++ による実行結果

コード:

a[0]=957813, a[1]=998424, m_A=000E9D75

a[0]=1981952, a[1]=167772170, m_A=001E1E38

a[0]=0, a[1]=0, m_A=00000000
a[0]=0, a[1]=0, m_A=001E3E00
gcc による実行結果

コード:

a[0]=-13213, a[1]=0, m_A=0xffffccc0

a[0]=-2144448376, a[1]=1, m_A=0x1802e5088

a[0]=0, a[1]=0, m_A=0x0
a[0]=0, a[1]=0, m_A=0x600064290
new FooB() だと、m_A も a[0] も初期化されています。

Re: nullptrチェックについて

#7

by yomi » 2年前

「非効率」と思ってるということですがどういう意味で言ってるのでしょうか?

例えば
A.ソースに書くのが面倒くさい(見た目的にも)
B.ifの処理が入ることが処理時間の無駄になるのではないか?
などなど

Re: nullptrチェックについて

#6

by YuO » 2年前

一応,nullptrチェックをしない,nullptrだった場合の挙動は一意に定められる,という条件下において,Null-Objectパターンというものがあります。
ただし,
  • 仮想関数を利用するため,速度的な効率を求める場合に非null側の呼び出しが多いと逆に不利になること
  • nullptrの代わりにnull objectを使うことを必須とする必要があること
  • 必ずしも目的となる挙動の一意性を保証できるとは限らないこと
が問題点でしょうか。

Re: nullptrチェックについて

#5

by Dixq (管理人) » 2年前

メンバ変数の初期化をいちいち初期化リストで一つ一つやらなければならないことや、
ポインタにnullが入る可能性がある設計上でnullチェックをしないといけないのは言語仕様上仕方のないことです。
JAVAのようにメンバ変数を定義するだけでデフォルト値が入ってくれたり、
Objective-Cのようにnull参照をしてもエラーにならなかったりするのは言語によるサポートがあるからです。
C++はメンバ変数の定義時には(staticでなければ)ゴミが入るし、null参照したら落ちるのはそのような言語仕様なのです。

で、工夫できないかと言えばある程度工夫は出来ます。
null確認したくないのであれば、必ずnullにならないような設計にすること。
例えばコンストラクタでnewした後deleteしないとか、
私の場合であればいつもスマートポインタリストにUIパーツやゲームのタスクなどを入れてそれをforで回します。

list<shared_ptr<A>> _list;
_list.add(make_shared<A>());
_list.add(make_shared<A>());
for(auto a : _list){
  a->YYY();
}

こうすればnull確認が必要なくなります。

Re: nullptrチェックについて

#4

by maru » 2年前

やっていることが同じなので、回答も同じです。

このコードでは m_A は未初期化状態であり、nullptr ではなく不定です。
if (m_A) でnull チェックしても意味がありません。

コンパイルできたのであれば、実行して動作を確認してから投稿したら如何ですか。

Re: nullptrチェックについて

#3

by dowhile » 2年前

maruさん

本当ですね。
確認したところ、初期化されていないとエラーが出ました(笑)
書き直させて頂きます。

コード:

class FooA
{
public:

	BOOL Func() { return TRUE; }
};

class FooB
{
public:

	FooA* m_A;

	void Update()
	{
		for (;;) {
			if (m_A) {
				if (m_A->Func()) break;
			}
			m_A = new FooA();
		}
	}
};

int main()
{
	FooB fb;
	fb.Update();
}
これでどうですかね?
変数名などは変わってますが、やっていることは同じです。

改めて、よろしくお願いいたしますm(__)m

Re: nullptrチェックについて

#2

by maru » 2年前

このコードでは f は未初期化状態であり、nullptr ではなく不定です。
if (f) でnull チェックしても意味がありません。

また、このメンバ関数はクラスオブジェクトを参照していないし、仮想関数にもなっていないので、nullptr でも呼び出しできちゃうんです(規格的にはどうか知りませんが...)。

nullptrチェックについて

#1

by dowhile » 2年前

こんにちは。
現在、c++でクラス設計をしながらゲームを作っています。

早速ですが、以下のようなコードがあるとします。

コード:

class Foo
{
public:

	BOOL Func() { return TRUE; }

};

int main()
{
	Foo* f;

	for (;;) {
		if (f->Func()) break;
		f = new Foo();
	}

        delete f;
}
このままですと、fはnullptrですので、f->Func()のところで落ちるかと思います。
(まあ普通はこんな書き方しませんが・・・^^;)
そこで、以下のようにします。

コード:

		if (f) {
			if (f->Func()) break;
		}
fのFuncを呼ぶ前に、fのオブジェクトが存在するかどうかをチェックします。
こうすれば、ループ1週目はfのオブジェクトが作成され、二週目でFunc()が呼ばれるようになります。

しかし、毎度毎度このように条件式でオブジェクトが存在するかどうかをチェックするのは非常に非効率かと思います。
そこで、他に何か良い方法があれば教えていただきたいのですが、いかがでしょうか。(というかあるはず!)
ちなみに、c++の知識はある程度はある・・・つもりです。

どうぞよろしくお願いいたします。

ページトップ