I Edited this with my best effort. Hopefully it's now Minimal, Complete, and Verifiable Example
-
The problem is as it has been described in the title. I have a custom derived class from cocos2d::Layer (GameWorldLayer). it has a Pointer Data Member (m_bar). m_bar also has an std:vector property (m_container). I initialise the m_bar inside the overridden virtual init() of the GameWorldLayer. Because of this whenever I try to push something into m_container vector, I get EXP_BAD_ACCESS.
if I initialise the Pointer Data Member(m_bar) outside the virtual init() method then everything works fine.
In simple terms I just don't understand why initialising the pointer data member outside of the virtual init() method would work but completely fail when it is initialised inside.
I tried to simplify the codes and kept at its bare minimum if you try in your IDE (I am using xcode btw) you should get the same EXP_BAD_ACCESS Im keep getting. (I am sure you already know but you also need cocos2dx 3.6)
GameWorldLayer.h
#ifndef __Flide__GameWorldLayer__
#define __Flide__GameWorldLayer__
#include "cocos2d.h"
#include "bar.h"
class GameWorldLayer : public cocos2d::Layer
{
private:
Bar * m_bar;
public:
static cocos2d::Scene* createScene();
virtual bool init();
CREATE_FUNC(GameWorldLayer);
void AddSomethingToBar();
~GameWorldLayer();//destructor
};
GameWorldLayer.cpp
#include "GameWorldLayer.h"
GameWorldLayer::~GameWorldLayer()
{
delete m_bar;
}
cocos2d::Scene* GameWorldLayer::createScene()
{
// 'scene' is an autorelease object
auto scene = cocos2d::Scene::create();
// 'layer' is an autorelease object
auto layer = GameWorldLayer::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
bool GameWorldLayer::init()
{
//1. super init first
if ( !Layer::init())
{
return false;
}
m_bar = new Bar();
return true;
}
void GameWorldLayer::AddSomethingToBar()
{
m_bar->PushContainer();
}
Bar.h
#ifndef __Flide__bar__
#define __Flide__bar__
#include <vector>
#include <stdio.h>
using namespace cocos2d;
class Bar
{
private:
std::vector<int> m_container;
public:
Bar(); //constructor
~Bar();//destructor
void PushContainer(); //pushes something into m_container.
};
#endif /* defined(__Flide__bar__) */
Bar.cpp
#include "bar.h"
Bar::Bar()
{
}
Bar::~Bar()
{
m_container.clear();
}
void Bar::PushContainer()
{
m_container.push_back(1);//pushing an integer
}
I don't think its necessary but just for completeness. I initialise the GameWorldLayer then call the GameWorldLayer::AddSomethingToBar() inside the AppDelegate::applicationDidFinishLaunching().
bool AppDelegate::applicationDidFinishLaunching()
{
...
// create a scene. it's an autorelease object
auto scene = GameWorldLayer::createScene();
((GameWorldLayer*)scene)->AddSomethingToBar();
...
}
My money is on GameWorldLayer::init()
which doesn't get called the way you think it does. m_pBar
will belong to the layer that you create here: auto layer = GameWorldLayer::create();
, and won't belong to your returned Scene
object.
Therefore your Scene
object won't access m_pBar
, because m_pBar
doesn't exist in a cocos2d::Scene
. And casting won't do any good either in this case.
Also, this cast (((GameWorldLayer*)scene)
) is bad. You should at least use dynamic_cast