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

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

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

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

COCOS2D-X

COCOS2D-Xは、 2Dゲームを手軽に開発できるフレームワークのことです。 iPhone(iOS)向け、Android等に対応しており、 実質ワンソースで開発が可能です。

C++

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

Q&A

解決済

2回答

4427閲覧

イベントリスナーで外部クラスの変数を操作したい(ラムダ式内で外部クラスのメンバ変数を操作したい)

Paalon

総合スコア232

C++11

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

COCOS2D-X

COCOS2D-Xは、 2Dゲームを手軽に開発できるフレームワークのことです。 iPhone(iOS)向け、Android等に対応しており、 実質ワンソースで開発が可能です。

C++

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

0グッド

1クリップ

投稿2016/01/19 19:45

編集2016/01/19 19:57

C++11とCOCOS2D-X v3でゲームのプログラムを作ろうとしています。開発環境はMac OSX 10.9 / Xcode6.2です。キーボードからの入力を変数の状態に反映させるために、Testクラスのメンバ変数aを書き換えたいのですが、それ以前に読み込み?がかれこれ数ヶ月上手くできずに困っています。コードの大事そうなところは以下のとおりです。
###MainScene.h
'''C++
#include "cocos2d.h"

typedef cocos2d::Vector<Field *> FieldVector; // define FieldVector

class MainScene :public cocos2d::Layer {
protected:
MainScene();
virtual ~MainScene();
bool init() override;
public:
static cocos2d::Scene* createScene(); // シーン生成
void update(float dt) override;
CREATE_FUNC(MainScene);
private:
};
'''
###MainScene.cpp
'''C++
#include "MainScene.h"
#include "Test.h"
#include <iostream>
USING_NS_CC;

MainScene::MainScene()
{
}

MainScene::~MainScene() {
}

Scene* MainScene::createScene() {
auto scene = Scene::create(); // create scene
auto layer = MainScene::create();
scene->addChild(layer);
return scene;
}
bool MainScene::init() {
if (!Layer::init()) {
return false;
}
Test test;
auto listener = EventListenerKeyboard::create(); // イベントリスナーの生成
listener->onKeyPressed = [this, &test](EventKeyboard::KeyCode keyCode, Event* keyEvent) {
if (keyCode == EventKeyboard::KeyCode::KEY_W) {
std::cout << test.getA() << std::endl; // Testクラスでa=1と初期化したはずなのに変な値が表示される
}
};
this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this); // イベントディスパッチャー
this->scheduleUpdate();
return true;
}
void MainScene::update(float dt) {
// 毎フレーム実行される
}
'''
###Test.h
'''
#include "cocos2d.h"

class Test {
protected:
private:
int a;
public:
Test() {
a = 1;
};
virtual ~Test() {
};
void setA(int x) {
a = x;
}
int getA() {
return a;
}
};
'''
MainScene.cpp内のイベントリスナーのあたりのラムダ式のところで、'Test test'を参照キャプチャすれば良いのかと思っていたのですが、実行してみると(ビルドは通りました)394793527などのような変な値がアウトプットされます。

プログラムの方針としては、別クラスのメンバ変数であるグリッド座標で保持しているデータ(プレイヤーの位置等)をキーボード入力などのイベントによって変更したいのですが、このポイントで躓いて他にどのような方法があるかも分からず、困っています。アドバイスいただけると幸いです。

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

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

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

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

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

guest

回答2

0

ベストアンサー

testMainScene::init()のローカル変数(スタックに積まれる)なので、MainScene::init()が終わると、捨てられます。参照でキャプチャしていますので、見ている先は同じtestになりますが、関数を抜けて捨てられた後のその場所の値は不定になります。

どういうことかというと、ちょっと下記のコードを見てみてください。

C++

1#include <iostream> 2#include <functional> 3 4std::function<int()> hoge_ref() 5{ 6 int a = 10; 7 auto func = [&a](){return a;}; 8 return func; 9} 10 11std::function<int()> hoge_val() 12{ 13 int a = 10; 14 auto func = [a](){return a;}; 15 return func; 16} 17 18int main() 19{ 20 auto f_ref = hoge_ref(); 21 auto f_val = hoge_val(); 22 std::cout << u8" 参照キャプチャ: " << f_ref() << std::endl; 23 std::cout << u8"コピーキャプチャ: " << f_val() << std::endl; 24 return 0; 25}

hoge_ref()とhoge_val()どちらも10を返す関数を返す(誤字じゃないですよ)と思われますが、実際は参照キャプチャであるhoge_ref()はうまくいきません。これはaが捨てられて、不定になってしまったからです。

コードを直すのであれば、方法は二つです。

  • testを参照キャプチャではなくコピーキャプチャにする。(testが大きい場合は、パフォーマンスに影響が出るので注意)
  • MainSceneクラスのメンバー変数としてtestを管理し、this->testで見に行く。(testを再利用する場合はどんどん変わっていってしまうので注意)

関数を抜けても捨てられないようにnewでメモリ確保という手段もありますが、メモリ解放をどうすればいいのかがちょっとよくわからないです。スマートポインタを使えば、もしかしてうまくいくかも知れません。(ここら辺は誰か補足をお願いします)

投稿2016/01/19 20:45

編集2016/01/19 20:50
raccy

総合スコア21733

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

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

Chironian

2016/01/20 00:48

> testを参照キャプチャではなくコピーキャプチャにする。 ラムダ式内でtestに値を設定し、それを外部で使いたい場合はコピーキャプチャでは使えないですよ。外部で使わないのであればラムダ式内部でtestを定義すれば簡単かも。 その他はraccyさんの回答は優れていると思います。 後、testをMainSceneクラスのメンバー変数にすることに私も一票いれます。
Paalon

2016/01/22 12:02

なるほど、全然気づいていませんでした。今の場合、testはかなり大きく、どんどん更新していくのでMainsceneクラスのメンバ変数として管理することにしました。ありがとうございました。
guest

0

期待通りに動かない理由はraccyさんの説明の通りですね。

Testクラスがどのような使われ方をするのか判りませんので正しい解決方法になるかどうか判りませんが、raccyさんの方法に加えてstatic Test test;という方法もあります。
staticを付けてtestオブジェクトを静的領域に確保すればinit()メソッドを抜けてもオブジェクトは残り続けるので、ラムダ式の中からも問題なくアクセスできます。

ただ、キーボードイベントでtestをいくら書き換えたところでtestは誰からも見てもらえないところにあるので、やはりMainSceneクラスのメンバ変数にした方がいいような気もします。

投稿2016/01/19 21:57

catsforepaw

総合スコア5938

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問