How can I initialise this class in an array? - c++

I'm trying to make an array of class filePlayerGui and when I try to initialise it in the constructor it won't let me do so
class MainComponent : public Component,
public MenuBarModel
{
public:
//==============================================================================
/** Constructor */
MainComponent (Audio& audio_);
/** Destructor */
~MainComponent();
void resized() override;
//MenuBarEnums/Callbacks========================================================
enum Menus
{
FileMenu=0,
NumMenus
};
enum FileMenuItems
{
AudioPrefs = 1,
NumFileItems
};
StringArray getMenuBarNames() override;
PopupMenu getMenuForIndex (int topLevelMenuIndex, const String& menuName) override;
void menuItemSelected (int menuItemID, int topLevelMenuIndex) override;
private:
Audio& audio;
FilePlayerGui filePlayerGui[2] {audio.getFilePlayer(0), audio.getFilePlayer(1)};
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};
The filePlayerGui comes up with this error "Copying array element of type 'FilePlayerGui' invokes deleted constructor". I have tried initialising it in the .cpp file that I'll down below but then it tells me that I need an array initialiser
MainComponent::MainComponent (Audio& audio_) : audio (audio_)
{
setSize (500, 400);
addAndMakeVisible(filePlayerGui[0]);
addAndMakeVisible(filePlayerGui[1]);
}
MainComponent::~MainComponent()
{
}
void MainComponent::resized()
{
filePlayerGui[0].setBounds (0, 0, getWidth(), 40);
}
//MenuBarCallbacks==============================================================
StringArray MainComponent::getMenuBarNames()
{
const char* const names[] = { "File", 0 };
return StringArray (names);
}
PopupMenu MainComponent::getMenuForIndex (int topLevelMenuIndex, const String& menuName)
{
PopupMenu menu;
if (topLevelMenuIndex == 0)
menu.addItem(AudioPrefs, "Audio Prefrences", true, false);
return menu;
}
void MainComponent::menuItemSelected (int menuItemID, int topLevelMenuIndex)
{
if (topLevelMenuIndex == FileMenu)
{
if (menuItemID == AudioPrefs)
{
AudioDeviceSelectorComponent audioSettingsComp (audio.getAudioDeviceManager(),
0, 2, 2, 2, true, true, true, false);
audioSettingsComp.setSize (450, 350);
DialogWindow::showModalDialog ("Audio Settings",
&audioSettingsComp, this, Colours::lightgrey, true);
}
}
}

Copying array element of type FilePlayerGui invokes deleted constructor
Means that some variant this line is in the declaration of the FilePlayerGui:
FilePlayerGui(const FilePlayerGui&) = delete
Meaning that a FilePlayerGui cannot be copied: https://en.cppreference.com/w/cpp/language/copy_constructor#Deleted_implicitly-declared_copy_constructor
There are workarounds, but you are skirting the author of FilePlayerGui's intent for the class. So the correct answer should stop here. Any use of FilePlayerGui should be done through the the classes audio member, using either: audio.getFilePlayer(0) or audio.getFilePlayer(1). (If this is the only member of MainComponent in all likelihood MainComponent should be eliminated.)
If you want to know how to do bad things, which I would reject in any code review, you can either create filePointerGui as:
FilePointerGui* filePointerGui[2] which would be intialized as:
MainComponent::MainComponent(Audio& audio_) : audio(audio_), filePointerGui({ &audio.getFilePlayer(0), &audio.getFilePlayer(1) })
Access would be performed as:
*filePointerGui[0]
Live Example
reference_wrapper<FilePointerGui> filePointerGui[2] which would be initialized as:
MainComponent::MainComponent(Audio& audio_) : audio(audio_), filePointerGui({ audio.getFilePlayer(0), audio.getFilePlayer(1) })
Access would be performed as:
filePointerGui[0].get()
Live Example
It's probably worth stressing once more this is bad code because it tries to outsmart the language and work around the intent of the classes design. But this is c++ so you can do it.

Related

Initializing member variables with a lambda

Suppose I have a template class:
template<class T>
class Entity
{
public:
Entity(std::function<void(T*)> init, int idx) : index(idx)
{
init(data);
}
T* getData(){ return Data; }
private:
int index;
T* data;
};
And I create an instance of the class as so:
Entity<Button> myEnt([](Button* button){
button = new Button();
/* some complex, **unique**, initialization of button */
}, 1);
This will compile, but when I call getData() and attempt to use the pointer returned in some other function the program crashes. I assume its because there is an error where data doesn't get properly initialized, but I cant tell why!
fwiw I can get the program to run as desired if I change the Entity constructor to:
Entity(std::function<T*(void)> init, int idx) : index(idx)
{
data = init();
}
and then call it as so:
Entity<Button> myEnt([](){
Button* button = new Button();
/* some complex, **unique**, initialization of button */
return button;
}, 1);
But in my opinion that's an undesirable way of doing it, and the first method should work, im just missing something.
You are passing data to init() by value, which means the lambda is receiving a copy of data. So any value the lambda assigns to its input parameter will be assigned to the copy and not reflected back to data.
You need to pass data by reference instead, eg:
template<class T>
class Entity
{
public:
Entity(std::function<void(T*&)> init, int idx) : index(idx)
{
init(data);
}
T* getData(){ return data; }
private:
int index;
T* data;
};
Entity<Button> myEnt([](Button* &button){
button = new Button();
/* some complex, **unique**, initialization of button */
}, 1);
If you want to initialize the pointer member, you need a reference or pointer to the member pointer, not the value of the pointer.
template<class T>
class entity
{
public:
Entity(std::function<void(T**)> init, int idx) : index(idx)
{
init(&data);
}
T* getData(){ return data; }
Private:
int index;
T* data;
}
Use it like this:
Entity<Button> myEnt([](Button** button){
// you need a pointer to the pointer in order to initialize it
*button = new Button();
/* some complex, **unique**, initialization of button */
}, 1);

C++ access private member from C style function pointer initialized with lambda

Here is a simple window class (members omitted for brevity):
class window {
public:
window();
window(const std::string& title, const gt::size2d& size, bool visible = true, bool fullscreen = false);
NO_COPY(window);
window(window&& o);
window& operator=(window&& o);
using close_callback = std::function<void()>;
// members omitted ...
private:
struct impl;
struct impl_deleter {
void operator()(impl* impl);
};
std::unique_ptr<impl, impl_deleter> m_pimpl;
close_callback m_close_callback = []() { DD("Close callback"); };
// ...
};
My goal is to call m_close_callback from GLFW window system, and I could implement something like this:
void close_callback_indirection(GLFWwindow* win)
{
gt::window* winptr = static_cast<gt::window*>(glfwGetWindowUserPointer(win));
if (winptr != nullptr) {
winptr->m_close_callback(); // DOES NOT COMPILE
}
}
gt::window::window(const std::string & title, const gt::size2d & size, bool visible, bool fullscreen)
: m_pimpl{ nullptr }, m_close_callback{ []() {} }, m_size_callback{ [](const gt::size2d&) { } }
{
// omitted GLFW and GL initialization here ...
GLFWwindow* win = glfwCreateWindow(size.x, size.y, title.c_str(), nullptr, nullptr);
m_pimpl.reset(new gt::window::impl);
m_pimpl->glfw_win = win;
glfwSetWindowUserPointer(win, this);
glfwSetWindowCloseCallback(win, close_callback_indirection);
// omitted rest ...
}
This, as expected, does not compile with message "'gt::window::m_close_callback': cannot access private member declared in class 'gt::window'".
However if I implement it like this:
gt::window::window(const std::string & title, const gt::size2d & size, bool visible, bool fullscreen)
: m_pimpl{ nullptr }, m_close_callback{ []() {} }, m_size_callback{ [](const gt::size2d&) { } }
{
// omitted GLFW and GL initialization here ...
GLFWwindow* win = glfwCreateWindow(size.x, size.y, title.c_str(), nullptr, nullptr);
m_pimpl.reset(new gt::window::impl);
m_pimpl->glfw_win = win;
glfwSetWindowUserPointer(win, this);
// using lambda instead of function pointer
glfwSetWindowCloseCallback(win, [](GLFWwindow* win) {
gt::window* winptr = static_cast<gt::window*>(glfwGetWindowUserPointer(win));
if (winptr != nullptr) {
// Accessing private member here
winptr->m_close_callback(); // WHY THIS WORKS?
}
});
// omitted rest ...
}
Now it compiles and it works, if I press window close button I can see the debug message.
My understanding is that lambda without capture list can and in this case will be cast to function pointer so I guess that compiler will generate function code somewhere and pass in a pointer to that, but why does it have access to private member of window object? Is the generated function private member of window (or a friend)?
Can I rely on this behavior or is this something that is considered to be undefined?
I am using MSVC++ compiler
Microsoft (R) C/C++ Optimizing Compiler Version 19.16.27026.1 for x86
All lambdas have access to whatever is accessible at the point of their declaration. If you create a lambda in a member function of a class, that lambda can access anything that the member function itself would have access to. Always.
When a captureless lambda is converted to a function pointer, the function referred to by that pointer is identical to the lambda itself. Including its accessibility.

Impossible to store cocos2d::Animation * in a std::vector of structure?

I work on a project made with cocos2d-x framework (c++).
In my Player class, I have to manage the animations.
Iinitially I had this code that worked without any problem:
First, the animation object is a cocos2d Class cocos2d::Animation. Just remember that this object contains a cocos2d::Vector<AnimationFrame*> _frames; member.
Doc: http://www.cocos2d-x.org/reference/native-cpp/V3.5/d3/dc5/classcocos2d_1_1_animation.html#a0fdc0be158df7e09d04644be353db056
class Player : public cocos2d::Sprite {
private:
cocos2d::Map<std::string, cocos2d::Animation*> animations;
cocos2d::Vector<cocos2d::SpriteFrame*> getAnimation(const char *format, int frameStart, int count);
void update(float delta) override;
bool init() override;
public:
static Player* create();
bool init() override;
//...
};
And the implementation side:
bool Player::init() {
//...
animations.insert("idleN", Animation::createWithSpriteFrames(getAnimation("%04d", 207, 9), 0.1));
//...
}
Vector<SpriteFrame*> Player::getAnimation(const char *format, int frameStart, int count) {
auto spriteCache = SpriteFrameCache::getInstance();
Vector<SpriteFrame*> animFrames;
char str[100] = {0};
for (int i = 1; i <= count; i++)
{
sprintf(str, format, frameStart);
log("%s", str);
animFrames.pushBack(spriteCache->getSpriteFrameByName(str));
frameStart++;
}
return animFrames;
}
//later in the code execution
void Player::manageIdle() {
auto idleAnim = Animate::create(animations[0].anim);
runAction(idleAnim);
}
You can see each Animation is contained in cocos2d::Map<std::string, cocos2d::Animation*> and as I say before, this code worked perfectly, no error.
But I needed some more informations in addition to the name and the object itself so I decided to use a structure to store all infos for each animation. And I replaced the cocos2d::Map<std::string, cocos2d::Animation*> by std::vector<animData> with animData as structure. I refactored the code like so:
class Player : public cocos2d::Sprite {
public:
typedef struct animation {
std::string name;
cocos2d::Animation* anim;
//all others info needed, not relevant here, (just several enum type variables)
} animData;
private:
std::vector<animData > animations; //the new container
//rest of code stay unchanged
};
The changes in the implementation side:
bool Player::init() {
//...
animations.push_back({"idleN", Animation::createWithSpriteFrames(getAnimation("%04d", 207, 9), 0.1)});
//no problem here...
}
But now, when I try to create a new anim with a animation saved in my container (vector) I get a SegV on this line:
void Player::manageIdle() {
auto idleAnim = Animate::create(animations[0].anim); //SegV here, in Animate::create() funct
runAction(idleAnim);
}
After search, I find that each structure member anim which is type of cocos2d::Animation*, now conatains a empty cocos2d::Vector<AnimationFrame*> _frames; and there is the problem !
It’s as if they lose the cocos2d::Vector<AnimationFrame*> ref or something like that.
So my question is why cocos2d::Vector<AnimationFrame*> become empty with my refactored code and not whith the previous one ?
I found this with test like that:
auto test = animList[0].anim->getFrames();
if (test.empty()) {
log("empty"); //The test output empty
}
Debugguer screen in the end of the init() funct:
Debugguer screen in Player::manageIdle() funct:
Edit: when I add animations.back().anim->retain(); right after the line to add an element in the vector, it solves the problem !
animations.push_back({"idleN", Animation::createWithSpriteFrames(getAnimation("%04d", 207, 9), 0.1)});
animations.back().anim->retain();
Because cocos2d::Animation* inherit from cocos2d::Ref, it is an auto-release object. When used inside a cocos2d container like cocos2d::Map or cocos2d::Vector, it is auto managed by the container itself. But I use a std::vector so I lose the ref I think. Something like that.
Now I need to find a way to get rid of this additional line of code because this multiple by twice my number of line here !
So new question here: How I can get rid of the fact I have to call animations.back().anim->retain(); each time I add a new element in my vector ?
You might create a wrapper around Ref, which "retains" ownership, and store this wrapper instead, sort of a std::unique_ptr e.g.
template<typename T> class RefOwner {
public:
RefOwner(T *t) : ref(t) {
ref->retain();
}
~RefOwner() {
ref->release();
}
T *operator->() { return ref; }
private:
T *ref;
};
and then use it as
struct animData {
std::string name;
RefOwner<cocos2d::Animation> anim;
//all others info needed, not relevant here, (just several enum type variables)
};
Disclaimer: I have no experience with cocos2d-x, just looked at Animation and Ref

Virtual function issue in C++ [duplicate]

This question already has answers here:
Why is virtual function not being called?
(6 answers)
Closed 9 years ago.
AoA,
I am making a console game of chess, But I am stuck at polymorphism, below is the classes and functions definitions
/* old Part
//Base Class
class Piece /*Parent class */
{
protected:
Position* pCoord;
std::string color;
char symbol;
public:
Piece(Position* Coord,std::string Color,char symbol);
Position GetCurrentPos();
std::string GetColor();
void SetColor(std::string color);
void Draw();
virtual bool SetPos(Position* newPos){MessageBox(NULL,L"Virtual Running",L"Error",MB_OK); return true;};
virtual ~Piece();
};
/* Inherited classes */
//Child classes
class Pawn: public Piece
{
private:
std::vector<Position>* allowPos;
public:
Pawn(Position* Coord,std::string Color,char symbol);
~Pawn();
std::vector<Position>* GetThreatendFields();
bool isValidMove(Position* newPos);
bool SetPos(Position* newPos);
};
//Child classes
class Bishops: public Piece
{
private:
std::vector<Position>* allowPos;
public:
Bishops(Position* Coord,std::string Color,char symbol);
~Bishops();
std::vector<Position>* GetThreatendFields();
bool isValidMove(Position* newPos);
bool SetPos(Position* newPos);
};
//Here is the implementation of child class function SetPos
bool Pawn::SetPos(Position* newPos)
{
bool isSet = false;
this->pCoord = new Position();
this->pCoord = newPos;
isSet = true;
MessageBox(NULL,L"Child function running",L"Yuhuu!",MB_OK);
return isSet;
}
class ChessBoard
{
private:
Position ptr; //dummy
int SelectedPiece;
vector<Piece> pPieceSet;
bool isSelected;
public:
ChessBoard();
~ChessBoard();
void ShowPieces(Player *p1,Player *p2);
void Draw();
void MouseActivity();
void Place(Piece& p);
};
//it just shows the peices acquired from player objects..dummy vector pointer
void ChessBoard::ShowPieces(Player* p1,Player* p2)
{
std::vector<Piece>* vPiece = p1->GetPieces();
for( int i=0;i<vPiece->size();i++ )
{
Piece& piece = vPiece->at(i);
Place(piece);
piece.Draw();
}
vPiece = p2->GetPieces();
for( int i=0;i<vPiece->size();i++ )
{
Piece& piece = vPiece->at(i);
Place(piece);
piece.Draw();
}
}
*/
/*new part
I did what you say
Player::std::vector<Piece*> *vPieceSet;
Player::Player(int turn)
{
this->turn = turn%2;
this->vPieceSet = new std::vector<Piece*>;
}
void Player::Initialize() //Initial and final ranges for position
{
//Initialization of pieces to their respective position
Position pos;
Piece *pPiece;
if( this->turn == 0 )
{
this->SetName("Player 1");
for( int i=8;i<16;i++ )
{
pos.SetPosition(i);
Pawn pPawn(&pos,"blue",'P');
pPiece = &pPawn;
this->vPieceSet->push_back(pPiece);
}
//other classes same as above
}
It runs fine at initialzation function(stores all classes fine) but when use function to get the vector object
std::vector<Piece*>* Player::GetPieces()
{
std::vector<Piece*>* tPieces = this->vPieceSet;
return tPieces;
}
//In main.cpp
it doesnot return the vector object
Player p1(0),p2(1);
p1.Initialize();
p2.Initialize(); //initialization done perfectly while debugging
vector<Piece*> *obj = p1.GetPieces(); //returns garbage
Piece* pObj = obj->at(0); //garbage
cout<<pObj->GetColor(); // garbage
*/new part
Sounds like I have another problem!
When you use polymorphism, what you are really trying to do is instantiate an object of derived type and call the methods on that object through a pointer or reference to the base object.
class Foo
{
public:
virtual void DoIt () { cout << "Foo"; }
};
class Bar
:
public Foo
{
public:
void DoIt () { cout << "Bar"; }
};
int main()
{
Foo* foo = new Bar;
foo->DoIt(); // OUTPUT = "Bar"
Foo& fooRef = *foo;
fooRef.DoIt(); // OUTPUT = "Bar"
}
In order for this to work, you need to use either a pointer or a reference to the object. You can't make a copy of the object using a the base class. If you make a copy, you will slice the object.
int main()
{
Foo* foo = new Bar;
foo->DoIt(); // OK, output = "Bar"
Foo fooCopy = *foo; // OOPS! sliced Bar
fooCopy.DoIt(); // WRONG -- output = "Foo"
}
In your code, the Piece class is intended to be polymorphic, and in your ChessBoard class you have a vector of this class:
class ChessBoard
{
private:
vector<Piece> pPieceSet;
};
Since this is a vector of the Piece object itself, and not a pointer-to-Piece, anything you put in here will be sliced. You need to change pPieceSet to be a vector of pointers-to-Piece:
vector <Piece*> pPieceSet;
You have further problems in Initialize, which need to be refactored anyway. For one thing, you have another vector of Piece objects, and there are two problems here. First, it needs to be a vector of pointers, and second, why do you need another vector at all when there is already one associated with the ChessBoard? I didn't thouroughly examine your code so maybe you do need it, but this seems like an error. There should probably just be one collection of pieces, in the ChessBoard.
In your Initialize method:
Piece *pPiece;
// ...
Pawn pPawn(&pos,"blue",'P');
pPiece = &pPawn;
vPieceSet.push_back(*pPiece);
There are a couple of problems. One, you are pushing back a sliced copy of the Piece, which will be fixed when you change your vector to store pointers. Second, if you just change this like so:
Piece *pPiece;
// ...
Pawn pPawn(&pos,"blue",'P');
pPiece = &pPawn;
vPieceSet.push_back(pPiece); // <-- not dereferencing
You will have a new problem because you'll be storing the pointer to a local (automatic) variable. Best is to do this:
Piece* pPiece = new Pawn (...);
// ...
vPieceSet.push_back (pPiece);
Please don't forget to delete everything you new. This is best handled by using smart pointers rather than raw pointers. In C++03 we have auto_ptr, but those can't go in a vector. Instead you'll need to use Boost or something else, or just store raw pointers. In C++11, we now have unique_ptr (preferred) and shared_ptr, which can go in to a vector.
In C++11, the best solution here is to have a vector declared as:
vector <unique_ptr <Piece> > pPieceSet;
...unless you have some compelling need to use shared_ptr instead.
As others have mentioned, it is a slicing issue, and the issue is created here:
class Player
{
private:
std::string pName;
std::vector<Piece> vPieceSet; // <-- This is your problem
int turn;
public:
Player(int turn);
~Player();
void Initialize();
std::string GetName();
void SetName(std::string Name);
int GetTurn();
std::vector<Piece>* GetPieces();
};
You are storing them in the vector as instances of Piece, which is slicing off the details of the piece (e.g. the Bishop implementation). You should modify it to something like:
class Player
{
private:
std::string pName;
std::vector<Piece*> vPieceSet; // or better, use a smart pointer wrapper
int turn;
public:
Player(int turn);
~Player();
void Initialize();
std::string GetName();
void SetName(std::string Name);
int GetTurn();
std::vector<Piece*> GetPieces(); // note this change as well
};
With your additional question/edit, you are getting another unrelated problem:
void Player::Initialize() //Initial and final ranges for position
{
Position pos; // position is declared inside the scope of Initialize
Piece *pPiece;
if( this->turn == 0 )
{
this->SetName("Player 1");
for( int i=8;i<16;i++ )
{
pos.SetPosition(i);
Pawn pPawn(&pos,"blue",'P'); // you are passing the address of position to the Pawn, and Pawn is within the scope of this loop
pPiece = &pPawn; // you are storing the address of the Pawn
this->vPieceSet->push_back(pPiece);
}
// Pawn is now out of scope and pPiece points to the memory location Pawn *used* to be at (but will likely be overwritten soon).
// As soon as this function returns, you have the same problem with pos
}
You need to allocate those variables on the heap (hence the reason we suggested smart pointer wrappers).

copy local objects by reference

Here's my problem,
Class MClass {
public:
void Add(OtherClass* objects) {
_objects = objects;
}
private:
OtherClass* _objects;
}
//otherfile.cpp
void Setup() {
MClass myObj;
OtherClass obj[NUMBER_OF_OBJECTS];
//obj initialization here
//...
myObj.Add(obj);
}
It will cause a RT error because the *obj diminishes after the end of the function body.
But, how can make this one valid?
I like to initialized first an object before assigning it to other class.
EDIT
I don't want to use storage classes or something here, I just want a raw array since it is very expensive for me to use. Its functionality will not lessen my problem here.
So how do I do that in a raw-array style?
Class MClass {
public:
void Add(std::vector<OtherClass> objects) {
_objects = std::move(objects);
}
private:
std::vector<OtherClass> _objects;
}
//otherfile.cpp
void Setup() {
MClass myObj;
std::vector<OtherClass> obj(NUMBER_OF_OBJECTS);
myObj.Add(std::move(obj));
}
In your example, you store a pointer to a local array. If the method ends, the array goes out of scope and doesn't exist anymore.
This is the reason, your pointer is not valid anymore. If you want to solve this, learn about the scope of variables in C++.
It is not completely clear what you are trying to do, but you could store a collection of objects instead of a pointer:
class MClass
{
public:
void Add(const std::vector<OtherClass>& objects) {
objects_ = objects;
}
void Add(std::vector<OtherClass>&& objects) {
objects_ = std::move(objects);
}
private:
std::vector<OtherClass> objects_;
};
then
void Setup()
{
MClass myObj;
std::vector<OtherClass> obj(NUMBER_OF_OBJECTS);
//obj initialization here
//...
myObj.Add(std::move(obj)); // move obj's contents onto myObs's objects.
}
Stop using raw arrays, and use either std::vector or std::array. Then you don't have to worry about it anymore.
If you really want to do it manually, you have to copy is manually as well. Using e.g. std::vector and std::move is more effective, but here you go:
Class MClass {
public:
MClass()
: _objects(nullptr), _count(0)
{}
MClass(const MClass& other)
: _objects(nullptr), _count(0)
{
Add(other._objects, other._count);
}
~MClass()
{
if (_objects != nullptr)
delete [] _objects;
}
void Add(const OtherClass* objects, const size_t count)
{
if (_objects != nullptr)
delete [] _objects;
_objects = new [count];
for (size_t i = 0; i < count; i++)
_objects[i] = objects[i];
_count = count;
}
MClass& operator=(const MClass& other)
{
Add(other._objects, other._count);
}
private:
OtherClass* _objects;
size_t _count;
};
// ...
myObj.Add(obj, NUMBER_OF_OBJECTS);
As you can see, it's a lot of more code, which makes it harder to follow and debug, and also larger possibility of errors. And not as "effective" as I said above.