I have a class that acts as a node in a binary tree, one of the methods which I would like to call from inside that class is recursive, and needs to pass itself to the next node in the tree so that the next node knows its own parent. I dont want to store a class member parent because I would like to avoid using a shared_ptr.
The code looks something like this:
void MyClass::expand(MyClass* parent){
for (int i = 0; i < children.size; i ++){
children[i]->doSomethingWithParent(parent);
children[i]->expand(this);
}
return;
}
But I would like to pass a unique_ptr instead of a raw pointer. However, the pointer to 'this' is already wrapped elsewhere by a unique_ptr already, so I dont want to instantiate another. Is it possible to do this?
If there are any design patterns I should be aware of please let me know.
Any help appreciated
Don't use a pointer at all. You are not taking ownership, the argument is not optional, so use a reference:
void MyClass::expand(MyClass& parent){
for (int i = 0; i < children.size; i ++){
children[i]->doSomethingWithParent(parent);
children[i]->expand(*this);
}
return;
}
All of your code will perform the same, and it is safer etc.
If you ever have a situation where you want to pass a non-owning pointer that is guaranteed to be non-null (which appears to be the case here), then you probably want to just use a reference instead.
In your case, depending on what doSomethingWithParent performs, you'd probably actually want a const reference as well:
void MyClass::doSomethingWithParent(const MyClass& parent) {
// who knows?
}
void MyClass::expand(const MyClass& parent) {
for (int i = 0; i < children.size; i ++){
children[i]->doSomethingWithParent(parent);
children[i]->expand(*this);
}
}
Related
So, I have an array of a class called "Customer"
Customer** customersarray[] = new Customer*[customer];
I'm receiving int customer with cin.
anyways, in customer.cpp, there is a method called void deactivate().
which goes like this:
void Custmoer::deactivate()
{
if (this != NULL)
remove this;
//this = NULL; I want to do this but it doesn't work.
}
and the purpose of this is to remove it from customer array when satisfies a certain condition. So for example,
for (int i = customer - 1; i >= 0; i--)
{
if (customersarray[i]->getAngerLevel() == 5) {
customersarray[i]->deactivate();
}
for (int z = i; i < customer - 1; i++) {
*(customersarray + z) = *(customersarray + z + 1);
}
customer--;
}
so my first questions are:
why does this = NULL not work?
is there a simpler way to remove something from pointer array when a condition is satisfied? (for example, remove all customers that has anger level of 5.)
Your mistake is thinking that you can remove something from a Customer* array by some magic inside the Customer class, but that's not true. Just remove a customer from the customer array where ever the customer array is. For instance using remove_if
#include <algorithm>
Customer** customersarray = new Customer*[customer];
...
customer = std::remove_if(customersarray, customersarray + customer,
[](Customer* c) { return c->anger() == 5; }) - customersarray;
This updates the customer variable to be the new size of the array, but doesn't free or reallocate any memory. Since you are using dynamic arrays and pointers you are responsible for that.
Which is why you should really not be using pointers or arrays, but using vectors instead.
std::vector<Customer> customerVector;
Life will be so much simpler.
Type of "this" is a constant pointer which means you cant change where it points
Your function can return a boolean and if its true just set your pointer to null
You'll be much better off using a std::vector, all memory memory management gets much safer. You cannot modify the this pointer, but that would be meaningless anyway:
It is a local variable, so any other pointer outside would not be changed, not even the one you called the function on (x->f(): the value of x is copied into this).
It contains the address of the current object - the current object is at a specific memory location and cannot be moved away from (not to be mixed up with 'moving' in the context of move semantics!).
You can, however, delete the current object (but I don't say you should!!!):
class Customer
{
static std::vector<Customer*> customers;
public:
void commitSuicide()
{
auto i = customers.find(this);
if(i != customers.end())
customers.erase(i);
delete this;
}
}
Might look strange, but is legal. But it is dangerous as well. You need to be absolutely sure that you do not use the this pointer or any other poiner to the current object any more afterwards (accessing non-static members, calling non-static functions, etc), it would be undefined behaviour!
x->commitSuicide();
x->someFunction(); // invalid, undefined behaviour!!! (x is not alive any more)
Similar scenario:
class Customer
{
static std::vector<std::unique_ptr<Customer>> customers;
public:
void commitSuicide()
{
auto i = customers.find(this);
if(i != customers.end())
{
customers.erase(i); // even now, this is deleted!!! (smart pointer!)
this->someFunction(); // UNDEFINED BEHAVIOUR!
}
}
}
If handling it correctly, it works, sure. Your scenario might allow a much safer pattern, though:
class Customer
{
static std::vector<std::unique_ptr<Customer>> customers;
public:
Customer()
{
customers->push_back(this);
};
~Customer()
{
auto i = customers.find(this);
if(i != customers.end())
customers.erase(i);
}
}
There are numerous variations possible (some including smart pointers); which one is most appropriate depends on the use case, though...
First of all, attending to RAII idiom, you are trying to delete an object before using its destructor ~Customer(). You should try to improve the design of your Customer class through a smart use of constructor and destructor:
Customer() {// initialize resources}
~Customer() {// 'delete' resources previously created with 'new'}
void deactivate() {// other internal operations to be done before removing a customer}
Then, your constructor Customer() would initialize your internal class members and the destructor ~Customer() would release them if necessary, avoiding memory leaks.
The other question is, why do you not use another type of Standard Container as std::list<Customer>? It supports constant time removal of elements at any position:
std::list<Customer> customers
...
customers.remove_if([](Customer foo) { return foo.getAngerLevel() == 5; });
If you only expect to erase Customer instances once during the lifetime of the program the idea of using a std::vector<Customer> is also correct.
Trying to understand the example for weak_ptr in Stroustrup's TCPL (pp 995, 4th Ed.). I understand the goal is to grab into a shared pointer (to a neighbor asteroid) when needed. The example code is:
void owner()
{
//...
vector<shared_ptr<Asteroid>> va(100);
for (int i = 0; i < va.size(); ++i) {
va[i].reset(new Asteroid(weak_ptr<Asteroid>(va[neighbor]))); // why?
}
}
A lot of stuff is going on in the marked line. I don't understand why reset is used, and why the constructor accepts a weak_ptr? Can someone explain that line in more details?
Interpreting the earmarked line,- Asteroid() constructor will accept a weak_ptr as a parameter and returns a shared_ptr. vector element va[i] relinquished any earlier ownership by calling reset before accepting the new shared_ptr.
The simplified code will look like so: Every new Asteroid will have a pointer to another neighbouring Asteroid, this pointer should be a weak_ptr to avoid cyclic reference due to interconnecting Asteroid pointers.
vector<shared_ptr<Asteroid>> va(100);
for (int i = 0; i < va.size(); ++i)
{
shared_ptr<Asteroid>sp = va[neighbor];
weak_ptr<Asteroid> wp = sp;
shared_ptr<Asteroid>sp2 = make_shared<Asteroid>(wp);
va[i].reset(sp2);
}
The reset fuction is equivalent to the assign operator (=), the difference is that the assign operator adds the shared_ptr object as a shared owner of the Asteroid object's assets, increasing their use_count, while the reset() function makes the shared_ptr acquires ownership of p with a use count of 1, making all the other owners release their ownership.
So, in this code, reset is being used to make va[i] the unique owner of the object at the time.
I don't understand why, in this example, i cannot access a member function by dereferencing the object
Here it's the relevant part of the code
class Search
{
public:
void run();
private:
Result* result;
Result* extractResults()
};
the extractResults() is defined as follows
Result* Search::extractResults()
{
Result* ris;
//as soon as i know the size, i initialize ris
ris = new Result[numOfResults];
return ris;
}
Inside the run() function, i call extractResults to get a pointer to the internal ris object
result = extractResults();
Now, i would expect to be able to access the "result" object, inside run(), like this:
result[4]->doSomething();
But it doesn't work, i must use
result[4].doSomething();
Why is that?
EDIT
Ok, i modified the code in order to be able to use the dereferencing operator. I know it is not necessary to use pointers in this situation, i just used it as an exercise.
class Search
{
public:
void run();
private:
Result** resultPP;
Result* resultP;
Result* extractResults()
};
Result* Search::extractResults()
{
Risultato* ris;
//as soon as i know the size, i initialize ris
ris = new Risultato[numOfResults];
return ris;
}
Inside the run() function
resultP = extractResults();
resultPP = &resultP;
Now i can finally do:
resultPP->doSomething();
I know it's messy, i just wanted to do it like this, as a way of learning.
thanks!
result is a pointer to an array of Risultato. Therefore the objects inside of result are actually value types. If you really wanted to use the dereferencing operator you would have to declare result as a pointer to an array of pointers to Resultato. I hope that helps.
I'm an expert level Java programmer, trying to port my knowledge over to C++. This is not homework, just a concept that I'm trying to learn the C++ equivalent of.
What I'm trying to do, is "generate" a list of objects of a custom type using a loop. This is how I would do it in Java:
public class TestClass
{
private ArrayList<ExampleClass> _exampleObjects;
private int _numObjects = 10;
public void populateList()
{
_exampleObjects = new ArrayList<ExampleClass>();
for(int i = 0; i < _numObjects; i++)
{
_exampleObjects.add(new ExampleClass());
}
}
public void doStuffWithListItems()
{
for(ExampleClass e : _exampleObjects)
{
e.performAction();
}
}
}
Super simple stuff. Create a list, iterate through an arbitrary loop and add objects to it. Then, loop through those objects and use them for whatever purpose.
TestClass.h:
class TestClass
{
public:
// Constructor, copy constructor, destructor definitions
void populateList();
void doStuffWithListItems();
private:
std::vector<ExampleClass> _exampleObjects;
const int _numObjects = 10;
};
TestClass.cpp:
void TestClass::populateList()
{
for(int i = 0; i < _numObjects; i++)
{
ExampleObject obj;
_exampleObjects.push_back(obj);
/* What actually goes here in place of obj? */
}
}
void TestClass::doStuffWithListItems()
{
for(auto it = _exampleObjects.begin(); it != _exampleObjects.end(); it++)
{
/* What do i do with my iterator to access my object? */
}
}
Its my understanding that where I initialise my objects in the first loop, they go out of scope and die by the end of each loop iteration. Is that right? If so, how do I make a persistent instance?
I experimented with the shared_ptr<> from and was apparently able to store them persistently, but couldn't for the life of me work out how to dereference from an iterator of a shared_ptr<>.
I feel like this should be a really simple concept. I just can't seem to work it out. I've read a lot on C++ scope and loops. I just can't seem to find anything on both.
ExampleObject obj;
_exampleObjects.push_back(obj);
/* What actually goes here in place of obj? */
Nothing. What you have is correct, assuming ExampleClass has a working copy constructor. If your compiler supports C++11 (and since you're using auto, it at least partially does), you can save yourself a copy.
_exampleObjects.emplace_back();
This constructs an object in place in the vector, forwarding the arguments (none in this case) to a matching constructor (the default ctor, in this case). For accessing the object from the iterator, do this:
for(auto it = _exampleObjects.begin(); it != _exampleObjects.end(); it++)
{
it->performAction();
}
Again, C++11 can make things better here.
for(auto & obj : _exampleObjects)
{
obj.performAction();
}
Its my understanding that where I initialise my objects in the first
loop, they go out of scope and die by the end of each loop iteration.
Correct.
If so, how do I make a persistent instance?
vector<>::push_back takes care of this. It copies the parameter into the vector. In other words, it's not the same object that was created in the loop, it's a copy. You just need to ensure that ExampleClass has non-broken copy semantics.
couldn't for the life of me work out how to dereference from an
iterator of a shared_ptr<>
If you had an iterator into a vector of shared pointers, (call it it), you would dereference it, and call the member function of the stored object, like this:
(*it)->performAction();
// alternatively
(**it).performAction();
The ideal answer suggests a very bad idea - use post increment ++ on iterator in loop.
You should never ever use it in loops where you only need to iterate because postincrement must return the value the iterator had before it was incrementing; so, that previous value needs to be copied somewhere before.
It is just not good from performance perspective and a bad codestyle sign.
I am making several items, and need to set them as being interactable with each other.
Item i1 = Item("Item 1");
Item i2 = Item("Item 2");
Item i3 = Item("Item 3");
Item i4 = Item("Item 4");
i1.setInteractable({i2,i3});
i2.setInteractable({i1,i4});
i3.setInteractable({i1});
This is the method header for the setInteractable method in Item.
void setInteractable(Item i[]);
The interactable items are stored as such:
static Item interactableItems[25];
This doesn't work, the error occurs after the first curly brace. What is the correct way to do this in C++?
You don't want to store objects in your array (otherwise, they are copied), but references to objects.
Change your storage and interface like that:
void setInteractable(Item& i[]);
static Item& interactableItems[25];
I advise to look in google for:
copy constructor
pointer vs object vs reference
C++ doesn't make dynamic lists as easily as you are trying.
To make the dynamic lists you need to first declare a dynamic list:
Item * dlist = new Item[2];
Set them:
dlist[0] = i1;
dlist[1] = i2;
then pass them into your function:
setInteractable(dlist);
Finally you have to remember to clean your memory:
delete [] dlist;
Or... you do this with the standard template library.
std::vector<Item> temp1;
temp1.push_back(i1);
//... other sets
Your function should be:
void setInteractable(std::vector<Item> & list)
{
///
}
The call should be
setInteractable(temp1);
It's a wrong C++ syntax to pass an array initialization like that:
i1.setInteractable({i2,i3}); // error: invalid
In various way you can achieve this. The most straight forward way is to use std::vector.
First declare interactableItems as,
static vector<Item> interactableItems;
Now you don't need setInteractable(), if you make above variable public
Usage:
i1.interactableItems.push_back(Item("Item 2"));
i1.interactableItems.push_back(Item("Item 3"));
If you want to have variable private then you can just put a wrapper and put the push_back inside it.
I would solve the problem like so:
Change the method to work on one object at a time, and loop over them:
void setInteractable(Item &i);
for (int i = 0; i < 25; i++)
for (int j = i + 1; j < 25; j++)
items[i].setInteractable(items[j]);
Much cleaner to deal with. You can store them in a std::vector inside of the Item, and just with those.
I would suggest using one of the STL containers. My implementation will proceed thus:
// Method header for the setInteractable method
#include <vector>
class Item {
private:
// some declarations
public:
void setInteractable(vector<Item &>);
// some other declarations
};
Your implementation should them selectively push Item objects onto vectors before passing them into the function.
Refer to the Cplusplus Reference Site for some more readings on STL containers.