c++ - Creating class instance in function and using it later - c++

Can I do this:
static Toggle GetAutoUpdatedToggle(DWORD key, bool initialState = false)
{
Toggle tempToggle(key, initialState);
autoUpdateToggles.push_back(tempToggle); //This is static member - std::vector<Toggle>
return tempToggle;
}
And I'm also using it later like that:
void Toggle::UpdateAllFromFactory() //This is static function
{
for each (Toggle toggle in autoUpdateToggles)
{
toggle.Update();
}
}
Is this good way of doing it?
UPDATE 1 - After your suggestoins:
static Toggle* GetAutoUpdatedToggle(DWORD key, bool initialState = false)
{
Toggle *pToggle = new Toggle(key, initialState);
m_autoUpdateToggles.push_back(pToggle);
return pToggle;
}
void Toggle::UpdateAllFromFactory()
{
for (std::vector<Toggle*>::iterator it = m_autoUpdateToggles.begin(); it < m_autoUpdateToggles.end(); it++)
{
(*it)->Update();
}
}

No, this is not a good way of doing it, because you pass around copies of Toggle:
GetAutoUpdatedToggle returns a copy of the Toggle that it just pushed into the vector. It's not in itself a wrong thing to do, but any manipulations the caller may do on the returned toggle would not be reflected on the one you pushed onto the vector
The for loop goes through elements of the vector, creating a copy for use inside the loop body. Unless the Toggle itself has a pointer-like semantic, the Update() action would not be reflected on Toggle objects inside the vector.
To fix this issue, make GetAutoUpdatedToggle return a reference to the Toggle object that it just pushed onto the vector, and use a vector<Toggle>::iterator object to iterate through the stored toggles. This would let you operate on the actual objects, rather than on their copies.

Your static function returns a copy of the Toggle. .push_back will also create a copy of the toggle. Thus the Toggle you return is not in the autoUpdateToggles and cannot be updated later.
Toggle myToggle = GetAutoUpdatedToggle(key);
/* ... */
Toggle alternativToggle = myToggle;
// alternativToggle == myToggle is true
Toggle::UpdateAllFromFactory();
// alternativToggle == myToggle is still true
Also note that your current implementation of Toggle::UpdateAllFromFactory(); uses copies of Toggles if you didn't use iterators instead.
You'll have to provide a handle to your Toggle object. This can be a simple pointer or any other object that doesn't loose the identity of the specific Toggle when being copied.

Related

How to efficiently perform a list of transformations in place on an object in C++?

I'm new to C++ and am a bit confused by how references, values, and move semantics work. I want to implement a function that can take an event, apply a list of transforms, and output the transformed event.
Here's a code snippet:
std::vector<Event (*)(Event)> transforms = ...;
Event process(Event baseEvent) {
Event&& e = std::move(baseEvent);
for(auto fn: this->transforms) {
e = fn(e);
}
return e;
}
The requirements:
The baseEvent should not be modified in place by process. I believe this is achieved here since I am passing the event in by value.
The process method's copy of baseEvent should be modified in place by each transform. I want to be careful not to make any extra copies. Each transform function takes in the event as an rvalue reference. However, I'm not sure if this is being achieved.
I read up on move semantics and tried to reason through the code, but not sure if the requirements are being met.
Your transformation function takes an Event and returns a new Event. It is literally impossible to build a "should modify in place" function on top of that.
So your function is already pretty much as close as you can get to what you want, except for the rvalue reference thing. There's no point in doing that. You want to std::move into the function, so that the argument can be move-constructed, but otherwise just assign back to the one object you already have.
Event process(Event e) {
for(auto fn: this->transforms) {
e = fn(std::move(e));
}
return e;
}
If you want the transformation functions to actually modify in place, you need to give them the ability to do so:
std::vector<void (*)(Event&)> transforms = ...;
Event process(Event e) {
for(auto fn: this->transforms) {
fn(e);
}
return e;
}

Why can't I push_back an object into a vector of objects that belongs to another class?

What I'm trying to do here is to add Voter to a vector that belongs to RegLogBook and, RegLogBook is an object that is owned by my Election class. I don't know what I'm doing wrong here, the Voter object is not being added to the vector. The relevant codes are below, I've removed all the unnecessary parts.
Election.h
class Election
{
public:
Election();
~Election();
RegLogBook getRegLogBook();
private:
RegLogBook* _regLogBook;
};
Election.cpp
Election::Election()
{
_regLogBook = new RegLogBook();
}
RegLogBook Election::getRegLogBook() {
return *_regLogBook;
}
RegLogBook.h
class RegLogBook
{
public:
RegLogBook();
~RegLogBook();
vector<Voter*> getVoterList();
private:
vector<Voter*> _voterList;
};
RegLogBook.cpp
vector<Voter*> RegLogBook::getVoterList() {
return _voterList;
}
Committee.cpp register voter method
void Committee::RegVoter(RegLogBook logs) {
Voter *newVoter = new Voter();
logs.getVoterList().push_back(newVoter); //The voter is not added to the list
}
I call this in my main()
Election *Election2018 = new Election();
Committee com1 = new Committee();
com1.RegVoter(Election2018->getRegLogBook());
RegLogBook::getVoterList() returns your _voterList by value. That means it copies the whole vector and returns it. Then you add elements to that copy.
To fix this, simply change your
vector<Voter*> RegLogBook::getVoterList()
to
vector<Voter*>& RegLogBook::getVoterList()
// ^ notice the reference part
There is another problem that I initially missed. In your Committee::RegVoter method, you take the argument by value. That means the method will be invoked with a copy of your RegLogBook. You should also change
void Committee::RegVoter(RegLogBook logs)
to
void Committee::RegVoter(RegLogBook& logs)
// again notice the reference ^
Thanks to Lightness Races in Orbit for pointing that out
Remember - to work on the original object, not a copy of it, you should pass it either by a reference or a pointer. By default you should prefer passing by reference, unless you have strong argument to use pointers
I believe the problem is that you return the voter list by-value, meaning that a copy of the voter list is returned:
vector<Voter*> RegLogBook::getVoterList() {
return _voterList;
}
So this line:
logs.getVoterList().push_back(newVoter);
will modify the local copy instead of the value being stored in the object instance.
Try modifying your code to return a reference (by changing the return type to be vector<Voter*>&)
vector<Voter*>& RegLogBook::getVoterList() {
return _voterList;
}
or, maybe better, return a pointer:
vector<Voter*>* RegLogBook::getVoterList() {
return &_voterList;
}
I prefer the last alternative, as this makes it more obvious that the returned value can be modified.
From what I'm seeing your code shouldn't even compile: you're using the new keyword, but you're saving its returned value into a Committee, not into a Committee* as you should. If you are using an overloaded new operator, please post the whole code.

C++ Unrelated pointer changing after function call

I'm working on using pointers to add objects to a queue and ran into a weird behavioral problem I can't quite figure out.
Each object that gets added to the queue has a 'next' pointer that links them all together and I have a 'start' and 'end' pointer to keep track where each end of the queue is.
The problem I have is that when I pass the end pointer and the object (which is stored in pArray by its processID), it also changes the start pointer -- even though I'm not passing it to the function.
// snippet from my main.cpp
RQCount = 0;
if (RQCount == 0)
{
RQStart = &pArray[processID];
RQStart -> next = &pArray[processID];
endRQ = &pArray[processID];
pArray[processID].setStatus("Ready");
CPUHolder = RQStart;
CPU = RQStart -> CPUBurst;
RQStart ->pStatus = "Executing";
}
else
{
*endRQ = FCFS(endRQ, &pArray[processID]);
pArray[processID].setStatus("Ready")
}
RQCount++;
FCSC Method:
PCB FCFS (PCB *endRQ, PCB *obj)
{
endRQ -> next = obj;
endRQ = obj;
return *endRQ;
};
I've narrowed it down to the function, and what really stumps me is that I move those two lines of code to my main, it runs and behaves just fine. It's when I add the function it doesn't. I think it has to do with how I'm dealing with the pointers and dereferencing, but I could use some help understanding this. Thanks!
EDIT:
To emphasize, I'm not having an issue with variables not changing in the function, as someone marked this a duplicate question for. The issue is after the function is called, it changes RQStart (which is not passed to the function).
If I don't use a function, RQStart stay the same, when I use the function, RQStart changes to a different object.
If you do
RQStart = &pArray[processID];
// ...
endRQ = &pArray[processID];
and then pass endRQ to the function, that will be the same as if you passed RQStart.
So when you change endRQ->next that will also change RQStart->next.
This is one reason for the standard containers to have end() point one past the last element, and not to the last element.

How do I reference successive components (button1, button2, etc.)?

I need to get the number after the button to increment in a for loop. For example, button1 becomes button2, etc. I have tried appending a variable which increments but C++ Builder gives an error saying "Button is not a member of TMain." Is there any way to achieve the end goal or get around this?
You can't construct new identifiers from others at run time. The compiler is correct that Button really isn't a member of your TMain class.
Instead, build the string name of the component you want, and then call your form's FindComponent method to get the component with that name.
for (int i = 1; i <= 2; ++i) {
std::string name = "Button" + IntToStr(i);
TButton* button = dynamic_cast<TButton*>(this->FindComponent(name));
}
That requires that the buttons' Name properties be set accordingly.
Another solution is to forego the component names and put your objects in a proper container, like a vector. For example, you can override the Loaded method (which is where you can be sure all your form's components have been created) and fill a vector there:
void TMain::Loaded() {
TForm::Loaded();
this->m_buttons.push_back(Button1);
this->m_buttons.push_back(Button2);
}
Now when you want to iterate over your buttons, you just iterate over the vector instead:
for (std::vector<TButton*>::const_iterator it = m_buttons.begin();
it != m_buttons.end();
++it) {
// ...
}

Filling list inside object and accessing to it later

I'm sorry if the title isn't very explicit, but I'll try to explain it better. I'm not very familiar with c++ and I'm using openFrameworks for the first time. I'm trying to do something that's probably quite easy, at least in other languages it is, but I'm not being able to do it :(
I have a class Video and inside it I have an object list<ofImage> keyFrames; and several methods to interact with it like the following:
void addKeyFrame(ofImage img) {
if(keyFrames.size() == 0) {
keyFrames.push_front(img);
}
else {
keyFrames.push_back(img);
}
}
list<ofImage> * getKeyFrames() {
list<ofImage> *list = &keyFrames;
return list;
}
void clearKeyFrames() {
keyFrames.clear();
}
In other class I have several Video objects and I have a function that uses addKeyFrame(ofImage img) to fill the list for each object. In the end of that function if I print the list size it is greater than zero.
Inside draw() function I iterate each Video object and I try to draw each image inside their keyFrame list, but the list is always empty and I just filled it with images... I'm using getKeyFrames() function to return a pointer to the list. How can it be empty if I just added objects to it in another function and if I verified that the size was greater than zero? And if I try to debug the application I feel even more lost lol.
Please tell me if you need anymore information and if you know what I'm doing wrong. Thanks!
Ok, A few little things:
1- You shouldn't check for empty lists (or any other STL containers) like this:
if(keyFrames.size() == 0)
This is faster and more "stylish":
if(keyFrames.empty())
2- You've created an unnecessary variable here:
list<ofImage> * getKeyFrames() {
list<ofImage> *list = &keyFrames;
return list;
}
You could do just:
list<ofImage> * getKeyFrames() {
return &keyFrames;
}
3- Pointers are not (most times) the best solution in C++. A reference is the most used substitute, but it would be even better in htis case if you returned an iterator:
list<ofImage>::iterator GetBeginIterator() {
return keyFrames.begin();
}
This way you could use the iterator just like a pointer, increasing it to iterate trough the frames and dereferencing it (with * operator)...