I'm making a game with SDL that used libconfig to read some settings from a file. The problem is that I made a class called ClipList that contains a std::vector<SDL_Rect> to store the settings but when trying to add SDL_Rect objects to the vector, for some reason push_back does nothing and I end up with an empty vector.
This is the class:
class ClipList
{
public:
ClipList();
ClipList(int);
virtual ~ClipList();
void addClip(int,int,int,int);
void getClip(int,SDL_Rect*);
int getLength();
protected:
private:
std::vector<SDL_Rect> clips;
};
ClipList::ClipList(int l)
{
clips.reserve(l);
}
void ClipList::addClip(int x,int y,int w,int h){
SDL_Rect rect;
rect.x = x;
rect.y = y;
rect.w = w;
rect.h = h;
clips.push_back(rect);
}
void ClipList::getClip(int i,SDL_Rect* rect){
rect = &(clips.at(i));
}
int ClipList::getLength(){
return clips.size();
}
And this is the function where I initialize the ClipList object. This function gets called from main.
void set_clips(Config* placlips,ClipList* clips, ClipList* flipclips){
const Setting& root = placlips->getRoot();
int x,y,w,h;
try{
Setting& clipsett = root["clips"];
int cliplen = clipsett.getLength();
clips = new ClipList(cliplen);
flipclips = new ClipList(cliplen);
for(int i=0;i<cliplen;i++){
const Setting& c = clipsett[i];
if(!(c.lookupValue("x",x)&&c.lookupValue("y",y)&&c.lookupValue("w",w)&&c.lookupValue("h",h))){
continue;
}
clips->addClip(x,y,w,h);
}
}catch(const SettingNotFoundException &nfex){
cerr << "Setting not found at" << nfex.getPath() << endl;
}
}
Regardless of whether the ClipList objects get initialized in main or set_clips, clips.push_back(rect) doesn't work. The capacity of the vector changes but no object gets stored so I end up with a segfault if I try to do anything else with the vector, even checking if the vector is empty or not.
I am going to guess, the signature of the function
void set_clips(Config* placlips,ClipList* clips, ClipList* flipclips);
is the culprit. You are allocating memory for clips and flipclips in this function but since the pointers are passed by value, the calling function does not see the allocated memory.
If you change the function signature to:
void set_clips(Config* placlips, ClipList*& clips, ClipList*& flipclips);
your problems should go away.
clips.push_back(rect) is working fine. Your set_clips function allocates new ClipList instances but does not pass those pointers back to the caller. The caller is probably attempting to use a garbage pointer as an initialise instance and that is why you are getting a segfault.
You need to pass the created objects back. You should use something like std::shared_ptr<> to do that instead of bare pointers.
Update on how to do this without using std::shared_ptr<>:
You need to keep track of ownership and deal with exceptions. In terms of the actual passing, the rule I use (originally from Lakos in "Large Scale C++ Software Design") is that parameters that are return values (as you are attempting to use them) are pointers, and read-only parameters are by value or const-reference. Return values come first.
So, your set_clips function should look like this:
void set_clips(ClipList** clips, ClipList** flip_clips, Config const& placlips)
When you call set_clips you pass a pointer to each pointer that will receive the allocated value, and pass a const-reference to the placlips object that is not modified by the function.
You would all it something like this:
ClipList* clips = 0;
ClipList* flip_clips = 0;
set_clips(&clips, &flip_flips, placlips);
// ... then do whatever comes next.
But combining those rules with std::shared_ptr<> or boost::shared_ptr<> is better and the "modern C++" style.
Related
I'm starting with C++ programming and I believe I have got a grasp about pointers. However I'm trying to understand the best practices for pointers and functions while using struts.
Toy example code
I have made below Toy example code to exemplify two ways to perform same thing:
#include <stdio.h>
struct rectangle {
int width;
int length;
};
void printRect(rectangle rect) {
printf("Rectangle: width=%d, length=%d\n",rect.width, rect.length);
}
void doubleSizeRectangle_1(rectangle *rect) {
rect->width = rect->width*2;
rect->length = rect->length*2;
}
rectangle doubleSizeRectangle_2(rectangle rect) {
rectangle *r = ▭
r->width = r->width*2;
r->length = r->length*2;
return *r;
}
rectangle doubleSizeRectangle_3(rectangle rect) {
rect.width = rect.width*2;
rect.length = rect.length*2;
return rect;
}
int main()
{
rectangle rect;
rect.width = 2;
rect.length = 5;
rectangle *rect_pointer = new rectangle;
rect_pointer = ▭
printRect(rect);
printRect(*rect_pointer);
printf("Applying functions:\n");
doubleSizeRectangle_1(rect_pointer);
printRect(rect);
rect = doubleSizeRectangle_2(*rect_pointer);
printRect(rect);
rect = doubleSizeRectangle_3(*rect_pointer);
printRect(rect);
}
That code returns following output:
Rectangle: width=2, length=5
Rectangle: width=2, length=5
Applying functions:
Rectangle: width=4, length=10
Rectangle: width=8, length=20
Rectangle: width=16, length=40
The first two prints are just to check about pointers usage.
The remaining prints are to check the three functions doubleSizeRectangle_1, doubleSizeRectangle_2 and doubleSizeRectangle_3 that perform same actions in different ways. The first one returns void and uses a pointer as input, whereas the second and third one have a variable as input and return a rectangle struct. Third option seems better than second, but would like to confirm. I'm not sure about the first one compared to the rest.
Question
Which option would be better in terms of best practice and why? Is there any of these options better in terms of avoiding memory leaks? May there be any other ways using pointers, and would those be even better than those I posted?
"best" is rather subjective, but using something complicated when there is no need to is not "best" in any sense.
Don't use new. Don't use pointers when there is no need to. Prefer references over pointers when nullptr is not a valid paramter (it isn't in your case). Use const references to avoid copies:
#include <stdio.h>
struct rectangle {
int width;
int lenght;
};
void printRect(const rectangle& rect) {
printf("Rectangle: width=%d, lenght=%d\n",rect.width, rect.lenght);
}
void doubleSizeRectangle_3(rectangle& rect) {
rect.width = rect.width*2;
rect.lenght = rect.lenght*2;
}
int main()
{
rectangle rect;
rect.width = 2;
rect.lenght = 5;
doubleSizeRectangle_3(rect);
printRect(rect);
}
Your function passed a pointer and returned the modified parameter. You do not need both. I changed it to return nothing and take the paramter by reference, because passing a nullptr does not make sense here.
You should also use a constructor to initialize the structs members, and prefer the type safe C++-IO (std::cout) over the non-typesafe C-IO.
For further reading: Why should C++ programmers minimize use of 'new'?
I suggest you to avoid doing like this:
rectangle doubleSizeRectangle_2(rectangle rect) {
rectangle *r = ▭
r->width = r->width*2;
r->lenght = r->lenght*2;
return *r;
}
you don't need to access that parameter using a pointer inside the method, you could simply access to object, because it's a copy.
As best practice, in order to minimize the risk of memory leak, the suggestion is to use smart pointers like this:
std::unique_ptr<rectangle> smartptrToRectangle(std::make_unique<rectangle>());
a smart pointer is a class that implements the RAII idiom:
RAII explanation
a smart pointer does destroy the element for you as soon as it go out of scope.
I would not use pointers for a function that edits a rectangle struct at all:
void doubleSizeRectangle(rectangle& rect)
{
rect.width = rect.width*2;
rect.lenght = rect.lenght*2;
}
The main difference between passing a pointer and a reference is just that a pointer can be unassigned while a reference always references a rectangle struct.
Your doubleSizeRectangle_1 essentially does the same thing. You should consider checking if the pointer is assigned if you want to stick to using pointers.
doubleSizeRectangle_2 makes no sense. You are passing your struct by value which means your function receives a copy of it. You then create a pointer to this object, manipulate it through that pointer to return it as a value again. The use of the pointer is useless there.
doubleSizeRectangle_3 is just doubleSizeRectangle_2 without the weird pointer. I wouldn't use this, it does at least one copy (when passing to the function) and one move operation (returning the struct from the function) that isn't nessecary for a function that just want's to edit the struct. Stick to my suggestion or your doubleSizeRectangle_1.
I added a destructor to some code and it seems to be calling early and causing problems. I added a debug statement to see where it is being called and that made me even more confused. I understand that managing my own memory is not best practice but I wanted to try it out myself.
This is basically my GameObject class:
class GameObject
{
public:
int xCoord = 0, yCoord = 0, prevX, prevY;
int status = 0, weight = -1;
int id = -1;
GameObject(CommandComponent* commands,
PhysicsComponent* physics,
GraphicsComponent* graphics)
: commandComponent(commands),
physicsComponent(physics),
graphicsComponent(graphics)
{};
~GameObject()
{
std::cout << "Destructor called " << id << std::endl;
delete commandComponent;
delete physicsComponent;
delete graphicsComponent;
};
void update(World& world, int command, sf::Time dt)
{
commandComponent->update(*this, world, command);
physicsComponent->update(*this, world);
graphicsComponent->update(*this, dt);
};
void update(World& world, int command)
{
commandComponent->update(*this, world, command);
physicsComponent->update(*this, world);
};
sf::Sprite draw()
{
return *(graphicsComponent->draw());
};
void setCoords(int x, int y)
{
prevX = xCoord;
xCoord = x;
prevY = yCoord;
yCoord = y;
};
void setId(int newId)
{
id = newId;
}
private:
CommandComponent* commandComponent = NULL;
GraphicsComponent* graphicsComponent = NULL;
PhysicsComponent* physicsComponent = NULL;
};
This is the createPlayer Method:
GameObject* createPlayer(sf::Texture* text)
{
return new GameObject(new PlayerCommandComponent(), new PlayerPhysicsComponent(), new PlayerGraphicsComponent(text));
};
This is a method I invoke to add the new object to a vector based on if it is an active object or an inactive one I also add it to an array :
void World::addObject(GameObject object, int id, int type){
object.setId(id);
if (type == 0)
{
inactiveObjects.push_back(object);
}
else if (type == 1)
{
activeObjects.push_back(object);
}
}
Finally this is my test code that creates the Game Objects and calls the above function and where I see the destructors being called from:
void World::test()
{
// Player
std::cout << "Starting to create id 0\n";
addObject((*createPlayer(&(mTextures.get(Textures::PlayerCharacter)))), 0, 1);
activeObjects.at(0).setCoords(3, 3);
activeObjects.at(0).weight = 10;
std::cout << "Created id 0\n";
// Test Objects
std::cout << "Starting to create id 1\n";
addObject((*createPlayer(&(mTextures.get(Textures::PlayerCharacter)))), 1, 1);
activeObjects.at(1).setCoords(3, 4);
activeObjects.at(1).weight = 7;
std::cout << "Created id 1\n";
addObject((*createPlayer(&(mTextures.get(Textures::PlayerCharacter)))), 2, 1);
activeObjects.at(2).setCoords(5, 4);
activeObjects.at(2).weight = 2;
addObject((*createPlayer(&(mTextures.get(Textures::Enemy)))), 3, 1);
activeObjects.at(3).setCoords(6, 6);
activeObjects.at(3).weight = -1;
addObject((*createPlayer(&(mTextures.get(Textures::Enemy)))), 4, 1);
activeObjects.at(4).setCoords(1, 1);
activeObjects.at(4).weight = 0;
std::cout << "Done Creating Test Objects\n";
I guess my main question is how come the Destructors are being called? Im assuming its related to how I'm constructing the object in the createPlayer method, Perhaps it's going out of scope after I return it but I thought using the new keyword would prevent that from happening? I'm puzzled here.
Several things at play here.
GameObject* createPlayer(sf::Texture* text)
returns a dynamically allocated GameObject. This could be done better, read up on std::unique_ptr, but there is nothing strictly wrong here. I mention it mostly to point out std::unique_ptr and set up
addObject((*createPlayer(&(mTextures.get(Textures::PlayerCharacter)))), 0, 1);
because this is where thing start to go wrong. When you find code that uses new and dereferences and discards the the result, you're looking at a memory leak. You've lost the pointer to the dynamically allocated object and without the pointer it is next to impossible to find the allocation again so that you can delete it.
Storing the dereferenced object will invoke either the copy constructor or the assignment operator and at this point you need to consider The Rule of Three: If you need a to define a custom destructor, you probably need to define a custom assignment operator and a copy constructor. This is a standard example of when you need to observe the Rule of Three. What goes wrong is well-explained in the Rule of Three Link, so stop, read, and understand it before going any further. Failure to do this means the rest of this answer will be nigh-useless to you.
You cannot write good, non-trivial C++ code without a firm grip on the Rule of Three and all of its friends.
You can step around the Rule of Three here by changing
void World::addObject(GameObject object, int id, int type)
to
void World::addObject(GameObject * object, int id, int type)
and pass object by reference. This doesn't help much because
inactiveObjects.push_back(object);
is expecting an object, not a pointer.
You can change that as well, but should you? std::vector is at its absolute best when it directly contains an object. Pointers lead to pointer chasing, poor caching behaviour and ultimately suuuhhhfering. Don't store pointers unless you have a compelling reason to do so.
And if you do, manage the pointers with a std::unique_ptr beginning to end.
What I would do:
Jump straight over the Rule of Three and go to The Rule of Five.
Exterminate as many dynamically allocated variables as possible so that I don't need to do much work, if any, with point 2. This means no pointers for (or in) commandComponent, physicsComponent and graphicsComponent if possible.
Add a move constructor and move assignment operator to GameObject as well as CommandComponent, PhysicsComponent, and GraphicsComponent. Keep all resource management as close to the resource as possible. This allows you to keep higher level classes as ignorant as possible. If GraphicsComponent knows how to copy and move itself, GameObject doesn't need to know how to move it. This allows you to take advantage of The Rule of Zero, and the Rule of Zero should be what you strive for in all of your classes.
Use move semantics to get a GameObject, not a GameObject* from createPlayer down to the activeObjects and inactiveObjects vectors.
Enjoy the reduced memory management load.
I'm trying to avoid using global variables in an openCV project (I'll have my supervisor no doubt teach me as to why they are bad rah rah rah :) - but at the moment they seem to be the only way I can get information out of mouse and trackbar callback functions.
Using the mouse example - at the moment I have as globals:
vector<Point2d> vectorOfPoints;
int clickCount = 0;
At the moment I have this line in main:
setMouseCallback("test",onMouse, NULL);
Then above main:
void onMouse(int event, int x, int y, int f, void* ){
if(event == CV_EVENT_LBUTTONDOWN){
vectorOfPoints.push_back(Point(x,y));
clickCount++;
}
}
It is working, but what is the syntax to get read/write access to both vectorOfPoints and clickCount inside the callback function without using globals?
I have found this question online a few times but the answers are unclear to me or wont work. There are hints within comments as how to do it, but I am so far unable to interpret the jargon correctly.
I was hoping for something as simple as the syntax I use to pass variables as references to methods ...
void referenceExampleMethod(vector<Point2d>& referenceExample){
//do something with referenceExample...
}
...less convoluted the better
I'm scared to ask (jargon overload!) but maybe it's 100% relevant - what is void* ??
Any help appreciated
I agree with the first part of the #jschultz410's answer about the pointer to some place in memory. However, I disagree with using raw pointers in the wild.
You should define your own data type, holding all your data, it could be struct or class, or std::pair, or std::tuple, whatever, the choice is yours.
Then you create an object of that type and use its address in the last argument for setMouseCallback.
The main thing you must ensure - the life time of that object must cover the life time of the window. That is, the object must be created before the first call to onMouse and destroyed after the last one. You could do this by declaring the variable in the beginning of your main. Then the object will be created early after the program start and destroyed near its finish automatically by the compiler. Here is the example.
typedef std::pair<vector<Point2d>, int> data_holder_type; // note the absence of references, this pair holds std::vector and int
void onMouse(int event, int x, int y, int f, void* ptr){
if(event == CV_EVENT_LBUTTONDOWN){
data_holder_type *dholder = static_cast<data_holder_type *>(ptr);
dholder->first.push_back(Point(x,y));
dholder->second.clickCount++;
}
}
....
int main(void) {
data_holder_type dholder;
// add code to initialize your dholder;
...
setMouseCallback("test", onMouse, &dholder);
...
cv::waitKey(); // wait until the window is closed
// read values from dholder and process them
} //dhloder is deleted somewhere here
Another important thing is the concurrent access to this object. onMouse is called from the separate parallel thread, and if your dholder is read or modified both in main, and onMouse simultaneously while the window is open, race conditions will occur. In general, they usually cause unpredictable and very hard to catch bugs.
Everything is fine while your main doesn't access dholder until the window is closed.
As for your question about void *. Note the lines inside if in onMouse. ptr points to the object of type void. That object has no any members, first, or second, or any others. You'll get the compiler error if you'll try to access them using ptr (e.g. ptr->first). Therefore you have to cast this pointer to pointer to another type, that contains some info about the object it points to, data_holder_type * in this case.
Any pointer type can be cast to void *, and void * can be cast to any other pointer type. This allows you to have several different callbacks for different windows.
Beware of wrong casts! No checks is done by compiler.
This example shows how to set 3 different mouse callbacks for windows with different titles.
typedef blah-blah-blah1 data_holder_type1;
typedef blah-blah-blah2 data_holder_type2;
typedef blah-blah-blah3 data_holder_type3;
void onMouse1(int event, int x, int y, int f, void* ptr){
if(event == CV_EVENT_LBUTTONDOWN){
data_holder_type1 *dholder = static_cast<data_holder_type1 *>(ptr);
dholder->first.push_back(Point(x,y));
dholder->second.clickCount++;
}
}
void onMouse2(int event, int x, int y, int f, void* ptr){
if(event == CV_EVENT_LBUTTONDOWN){
data_holder_type2 *dholder = static_cast<data_holder_type2 *>(ptr);
// processing, related to another data type
}
}
void onMouse3(int event, int x, int y, int f, void* ptr){
if(event == CV_EVENT_LBUTTONDOWN){
data_holder_type3 *dholder = static_cast<data_holder_type3 *>(ptr);
// process
}
}
int main(void) {
data_holder_type1 dholder1;
data_holder_type2 dholder2;
data_holder_type3 dholder3;
// add code to initialize your dholders;
...
setMouseCallback("test1", onMouse1, &dholder1);
setMouseCallback("test2", onMouse2, &dholder2);
setMouseCallback("test3", onMouse3, &dholder3);
...
}
The last parameter to setMouseCallback is passed back to you when onMouse is called. That is what the void * is in onMouse: the pointer that you passed to setMouseCallback. A void * is a pointer to an unspecified type. You can think of it as a generic pointer to some place in memory.
In your case, you would likely pass the address of a struct that either contains or points to the variables that you want to have access to inside onMouse.
#include <utility>
...
typedef std::pair<std::vector<Point2d>&, int&> my_pair;
...
my_pair *p = new my_pair(vectorOfPoints, clickCount); // TODO: needs to be deallocated eventually
setMouseCallback("test", onMouse, p);
The above assumes that vectorOfPoints and clickCount are already allocated somewhere else (e.g. - dynamically, statically, on the main thread's stack, etc.) and will remain so for the duration of your callbacks. Then,
void onMouse(int event, int x, int y, int f, void *pptr)
{
my_pair *p = (my_pair*) pptr;
if(event == CV_EVENT_LBUTTONDOWN){
p->first.push_back(Point(x,y));
p->second++;
}
}
I am trying to create an object and everytime I create an object, I then store that object in a static class variable that is an array of all of the objects created.
I am new to c++ and have no idea how to accomplish this. I have done it in Java before, but I am stuck here.
Take this for example purposes:
class Rectangle
{
private:
int width;
int length;
// Code to create an array of Rectangle Objects
// that hold all the the Rectangles ever created
public:
Rectangle();
Rectangle(int x, int y);
};
Rectangle::Rectangle()
{
width = 0;
length = 0;
// code to add an instance of this object to an array of Rectangle Objects
}
Rectangle::Rectangle(int x, int y)
{
width = x;
length = y;
// code to add an instance of this object to an array of Rectangle Objects
}
Is this possible?
Since you have to use an array to keep all objects you have to define a constant maximum size, since the size of an array is fixed and cannot be changed. This means that you also have to define a variable that keeps track of how many elements the array has, so that you don't exceed its boundaries.
const int MAX_SIZE = 100;
class Rectangle
{
private:
int width;
int length;
static Rectangle* all_rectangles[MAX_SIZE];
static int rectangle_count;
public:
Rectangle();
Rectangle(int x, int y);
};
Then you define the static variable and add the objects to the array in the Rectangle constructor, for example:
//Define static variables
Rectangle* Rectangle::all_rectangles[MAX_SIZE];
int Rectangle::rectangle_count = 0;
//Constructor
Rectangle::Rectangle () {
all_rectangles[rectangle_count] = this;
rectangle_count++;
}
Since the array with rectangles (and its components) is private, you can only reach it from within the class. You can however define functions that are public, to reach the rectangles private variables. You can get the width of a rectangle by declaring a function
static int getWidth(int a){
return all_rectangles[a]->width;
}
and call it by cout << Rectangle::getWidth(2) // Get width of second element in array
However vectors are preferable to use before arrays since they are expandable and includes many build-in functions, such as add and remove elements.
Nowadays we tend to avoid plain array and normal pointers.
So go for smart pointers and STL containers.
As your objects will live and die, a vector may not be soon sparse, having lots of holes corresponding to the (deleted) objects you do not use anymore.
Another solution would be an unordered map (hash table). We then need a key. We will not think about transforming the value of a (the this) pointer to a int or long as it is a very dangerous way to go.
So we must pay for some unique id ( see boost uuid ). This is also costly for the computing time but all this mechanism will save you time ( for writing code documentation ).
We then need a smart pointer.
As you want to keep track of all the object created we will go for a mandatory "factory" function to create your objects. As they may not be uniquely owned the only choice left for the factory function is to reject a shared pointer.
This is not directly a shared pointer that may be stored inside our container as it would prevent us to easily get rid of the object once not needed anymore ( the shared pointer inside the container would still participate to the object count ).
Shared pointer may get a custom deleter that will let us do some housekeeping for the container
So this is a weak pointer ( that do not participate to the object count ( or in some very small extent( weak count ) ) that is chosen for our container.
Here is some code ( forgive me I chose widget and not rectangle ):
Our class that must inherit from this curious class ( e.g see Scott Meyers new book Effective Modern C++ item 19 )
class widget:public std::enable_shared_from_this<widget>
alias ( ~ typedef )
using widget_weakptr_cont_t = std::unordered_map<std::string,std::weak_ptr<widget>>;
using widget_smrtp_t = std::shared_ptr<widget>;
using uuid_t = boost::uuids::uuid;
The factory function
static widget_smrtp_t widget_factory(void);
The container
static widget_weakptr_cont_t widget_cont;
The constructor is private ( you may also prevent all the other form of copy or move construction to strengthen the rule )
private:
widget();
void self_emplace(void);
const uuid_t uuid_tag;
The custom deleter for the shared pointers
auto widgetDeleter = [](widget* pw) {
std::cout << "Widget deleter" << std::endl;
widget::widget_cont.erase(pw->uuid_to_string());
delete pw;
if ( widget::widget_cont.empty() )
std::cout << "No Widget left" << std::endl; };
The factory function
widget::widget_smrtp_t widget::widget_factory(void)
{
auto wshp = widget_smrtp_t(new widget(),widgetDeleter);
wshp->self_emplace();
return wshp;
}
The self_emplace function
void widget::self_emplace(void)
{
widget::widget_cont.emplace(uuid_to_string(),shared_from_this());
}
You may then use your factory function inside some other functions ( or main( ) )
auto pw = widget::widget_factory();
An example for retrieving our object from the container could be
for ( auto const & it : widget::widget_cont )
{
//if interested by uuid we normally do
// std::cout << it.first << std::endl;
//For exercice we do the following:
auto shp = it.second.lock();
if ( shp )
{
std::cout << shp->uuid_to_string() << std::endl;
}
}
In the execution below the function func ( not displayed here the post is already too long )
only makes a copy of a globally factored shared pointer (to one of our widget).
The container is not modified by what happened inside func.
func2 creates another local widget that is destroyed when leaving func2. container is shown at these 2 steps.
Finally the globally constructed widget is only destroyed at the end (of the main )
Hello world!
Widget elems are:
84871b52-0757-44c1-be23-fb83e69468c0
func
Widget elems are:
84871b52-0757-44c1-be23-fb83e69468c0
func2
Widget elems are:
b2aedb78-8bb0-427e-9ada-fce37384f7de
84871b52-0757-44c1-be23-fb83e69468c0
Widget deleter
Widget elems are:
84871b52-0757-44c1-be23-fb83e69468c0
bye !
Widget deleter
No Widget left
I hope all of this may help
NGI
EDIT 2016.08.21
I publish the "unabridged code" Code on Coliru
It will not be much clearer because when I first replied I tried also other syntax features just for test.
Anyway you have now all in hands ( sometimes I do not publish a full code in order to avoid the "homework" copy/paste problem )
Lately I tried to simplify my code without success, 2 thoughts:
class widget:public std::enable_shared_from_this < widget > { ... }; is already a CRTP
You can not use shared_from_this() when there is no shared_ptr < T > already existing SO: shared_from_this() causing bad_weak_ptr exception
I have a thread-class Buffer (own made class), and many derived classes such as BufferTypeA, BufferTypeB...
Since I have to synchronize them in a certain order, I'm giving any of them an integer which represents the order to run certain task. I also have to know inside each thread Buffer which one is next to run the task, so I'm passing every BufferType a reference to an integer which all of them must share and I didn't want to make it Global.
I got lost at any point and I don't see where.
First I create all the BufferTypes from a class where I also define that shared integer as:
int currentThreadOrder;
And when creating the BufferTypes:
int position = 0;
if (NULL == bufferA) {
bufferA = new BufferTypeA(¤tThreadOrder, ++position,
waitCondition);
}
if (NULL == bufferB) {
bufferB = new BufferPos(¤tThreadOrder, ++position,
waitCondition);
}
if (NULL == bufferC) {
bufferC = new BufferRtk(¤tThreadOrder, ++position,
waitCondition);
}
Then, in BufferTypeA header:
class BufferTypeA: public Buffer {
public:
BufferTypeA(int currentThreadOrder,
int threadConnectionOrder = 0,
QWaitCondition *waitCondition = NULL);
//..
}
And in cpp file:
BufferTypeA::BufferTypeA(int currentThreadOrder, int threadConnectionOrder, QWaitCondition *waitCondition):
Buffer(currentThreadOrder, threadConnectionOrder, waitCondition) { }
Now I'll show Buffer header:
class Buffer: public QThread {
public:
Buffer(int ¤tThreadOrder,
int threadConnectionOrder = 0,
QWaitCondition *waitCondition = NULL);
//...
protected:
QWaitCondition *waitCondition;
int threadConnectionOrder;
int ¤tThreadOrder; // Shared address
}
And finally the cpp:
Buffer::Buffer(int ¤tThreadOrder, int threadConnectionOrder, QWaitCondition *waitCondition) {
this->threadConnectionOrder = threadConnectionOrder;
this->waitCondition = waitCondition;
this->currentThreadOrder = currentThreadOrder;
}
And the error I'm getting is error: uninitialized reference member Buffer::currentThreadOrder.
I'm embarrased to ask, because it's going to be a simple problem with pointers and addresses, but I can't see where the problem is, so please help.
When you create a class with a data-member that is a reference, the reference needs to be assigned a value in the constructor initializer list.
References have to be given a value when they are created, they are not pointers. They have to start with a value and that value cannot be changed (while the contents that is pointed to by that value can be changed).
Essentially you can think of a reference as an alias for an existing variable. You can't give a friend a nickname if you don't have a friend :)
RESPONSE TO COMMENT:
You don't "share a reference" between objects. Each object will have its own reference to the same variable. When you "pass by reference" you are telling the compiler that you want the variable in your function to actually be the variable in your outer scope, rather than creating a new variable by value. This means that you only have one variable at one memory location. The reference is just memory in some other place that forwards you to that same memory location.
Think of this as call forwarding... I can have 15 phone numbers in 15 different countries. I can set them all up to forward calls to my cell in the US. So, people are calling me no matter which number they call.
Each of your classes just has another reference to forward the "phone calls" or variable reads/writes to that same memory location. So, you're not sharing a reference between classes, you're making sure that each class HAS a reference to the same underlying memory location.
Back to the metaphore, each class won't have the same phone, but each class' phone will forward to the same number (variable) none-the-less which lets them all set/get the same value in the end.
RESPONSE II:
Here's a simple example to get your head going, it's pretty easy to apply to your classes. I didn't compile it but it should work minus a typo or two possibly.
class A
{
public:
A(int& shared) : m_shared(shared)
{
//No actions needed, initializer list initializes
//reference above. We'll just increment the variable
//so you can see it's shared in main.
m_shared += 7;
}
void DoSomethingWithIt()
{
//Will always reflect value in main no matter which object
//we are talking about.
std::cout << m_shared << std::endl;
}
private:
//Reference variable, must be initialized in
//initializer list of constructor or you'll get the same
//compiler error again.
int& m_shared;
};
int main()
{
int my_shared_integer = 0;
//Create two A instances that share my_shared_integer.
//Both A's will initialize their internal reference to
//my_shared_integer as they will take it into their
//constructors "by reference" (see & in constructor
//signature) and save it in their initializer list.
A myFirstA(my_shared_integer);
A mySecondA(my_shared_integer);
//Prints 14 as both A's incremented it by 7 in constructors.
std::cout << my_shared_integer << std::endl;
}
you pass a pointer int* as 1st argument to BufferTypeA, which expects and int, while you said in your question you meant to use a int&. To do this, the ctor of BufferTypeA should take a int& and initialise it in an initialisation list (i.e. not within the { } part of the ctor) like
class BufferType {
int &Ref;
public:
BufferTypeA(int& ref) : Ref(ref) { /* ... */ }
};
and in your construction of BufferA you must not pass an address, but the reference, i.e.
int counter;
Buffer = new BufferType(counter);
You want code like this:
Buffer::Buffer(
int ¤tThreadOrder0,
const int threadConnectionOrder0,
QWaitCondition *const waitCondition0
) :
threadConnectionOrder(threadConnectionOrder0),
waitCondition(waitCondition0),
currentThreadOrder(currentThreadOrder0)
{}
The reason is related to the reason you cannot write
const double pi;
pi = 3.14;
but can write
const double pi = 3.14;
A reference is typically implemented as a constant pointer, to which one cannot assign an address after one has initialized the pointer. Your version of the code assigns, as in the first pi example. My version of the code initializes, as in the second pi example.