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.
Related
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);
}
}
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 wondering how one would go about returning a new object from a C++ function. For example, I have a SQLite wrapper which used to mix in Objective-C and I modifying it to be purely C++.
So, for example:
list<char*> * SqliteWrapper::RunQuery(const char *query)
{
list<char*> * result = new list<char*>();
//Process query
return result;
}
the issue that I can see in this, is that who owns the object? The calling class or the class that created the object? What is worse, is that this is very prone to memory leaks. If the caller object does not delete the newly created object, the app will end up with a memory leak.
Now that I think about this, this would make a lot of sense:
int SqliteWrapper::RunQuery(const char *query, list<char*>& result)
{
//Process query
return errorCode;
}
Are there any other approaches to this? I have been a C# programmer for a while and only now am starting to work heavily with C/C++.
Many programmers do this:
If it is a pointer that is returned, I am being given the object's identity (it's location in memory is unique) I must manage that. I am responsible for deleting it.
(Pointer = my job)
references however let you pretend you are being passed the object, to look at and use. you are not responsible for deleting these, something else is.
BUT:
"Naked pointers" may be frowned upon for code like this (it's very subjective) so some would say use a "unique_ptr" to that, these can be moved, and delete what they point to when deleted (unless the stuff is moved out of them), by returning one and not using it, it will be deleted.
(tell me if you want me to flesh this out, see also "shared_ptr" if multiple things have a pointer, this will delete what it points to when the last shared_ptr pointing to it is deleted)
Addendum 1
unique_ptr<list<char*>> SqliteWrapper::RunQuery(const char *query)
{
list<char*> * result = new list<char*>();
//Process query
return make_unique<list<char*>>(result);
}
Remember you can only move, not copy unique_ptrs
Well. You are right.
First example would be a bad style, since in such a code is hardly readable and it is hard to track bugs in it.
Usually people use the second approach with reference.
In the same way you can use pointer, allocating the return object before function call.
Third approach would be to use class instead of function. It is convinient if your function does complicated process with many parameters. In this case you store result as a data member of the class and ownership is obvious:
class SqliteWrapper {
...
class ProcessQuery {
public:
ProcessQuery():fQ(0),fP1(0){}
SetQuery(const char *query){ fQ = query; }
SetP1(int p1){ fP1 = p1; }
...
list<char*> GetResult(){ return fR; } // copy
int Run();
private:
const char *fQ;
int fP1;
...
list<char*> fR;
}
...
}
int SqliteWrapper::Process::Run()
{
//Process query
return errorCode;
}
I'm having a problem in my c++ game related with the vector.
I want to know if theres any code that tells me if a vector still exists.
Example (x = a structure that I created):
vector<x*> var;
var.push_back(new x);
var[5]->Pos_X = 10;
And now what i want:
delete var[5];
if(var[5] still exists){
var[5]->Pos_X = 20;
}
What could be the code for var[5] still exists?
Unless you've actually set the pointer to null after deleting it, there's no real way to determine whether that slot in the vector contains a pointer to a live object or not.
So you'd need to:
delete vec[5];
vec[5] = NULL;
Then you could test
if (vec[5] == NULL)
to determine if there was "really" something at that location or not.
There is no code for that, not without extra careful work in your deleting process. If you store smart pointers you can do it like this:
vector<unique_ptr<x>> var;
// assuming you actually do add 6 or more elements to the vector
...
var[5].reset();
if (var[5]) { ... }
You could use var.size() to see if the vector contains a pointer at var[5], but that won't tell you whether the pointer is valid.
You could create a small wrapper class:
template <class T>
class wrapper {
bool valid;
T *data_;
public:
wrapper(T *d): data_(d), valid(true) {}
del() { delete data; valid = false; }
bool isValid() { return valid; }
T *data() { return valid ? data : NULL; }
};
std::vector<wrapper<x> > var;
var[5].del();
if (var[5].valid())
var[5].data()->Pos_X = 20;
Personally, I'd prefer to just ensure that all the pointers are valid all the time though.
calling delete you are deallocating memory pointed by that x*, so you still have pointer to some memory address that do not contain anymore what you excpected.
If you want to remove elements from vector consider using "erase"; then, if you don't want to erase but simply "cancel" the Nth element, structure is yours.. put some bool flag inside your structure.
So I have the following code
class UserDB
{
private:
AccountInfo* _accounts[200] ; // store up to 200 accounts
public:
UserDB();
virtual ~UserDB();
}
UserDB::UserDB(){
//code for initializing it to null
}
UserDB::~UserDB(){
delete [] _accounts;
}
So basically I am trying to find this code to initialize _accounts to null but I cannot find a real answer, all the guides in the internet either say how to initialize an array, an object, or a pointer, but not something that is all three altogether, and even less how to initialize this kind of pointer to null, even whatever they are initializing [in the guides] looks very confusing, so I come once again to ask for help here.
Also, AccountInfo is just any random class.
use std::array or std::vector.
you don't delete[] _accounts because the array is a value -- it is an array of pointers. IOW, its size is not equal to a pointer.
Here's a std::vector approach:
class UserDB {
private:
std::vector<AccountInfo*> _accounts;
public:
UserDB() : _accounts(200, 0) {}
virtual ~UserDB() {}
};
However, you may prefer to use the vector's default initializer so you can use it to determine the number of accounts it holds.
Update in response to comments below:
Although there are reasons to hold an array of AccountInfo* pointers, you may also consider std::vector to hold an array of AccountInfos values:
class UserDB {
private:
std::vector<AccountInfo> _accounts;
public:
UserDB() : _accounts() {}
virtual ~UserDB() {}
void appendAccountInfo(const AccountInfo& info) {
this->_accounts.push_back(info);
}
};
std::vector will handle all your allocation and reallocation needs for you. It's also nice because it's dynamically resizable, and you won't be constrained to a fixed number of AccountInfos.
create a constant instead of the magic number 200 (not really necessary but it makes the code more readable and safer when later changing)
const int numberOfAccounts = 200;
AccountInfo* _accounts[numberOfAccounts]
UserDB::UserDB()
{
for (int i = 0; i < numberOfAccounts; ++i)
{
_accounts[i] = 0;
}
}
now you have you 200 zeroed pointers.
also have a habit of putting private members at the end of the class and public at the start,
especially by bigger classes you want to see the public stuff first, the private stuff you normally
don't want somebody to mess with.
class C
{
public:
protected:
private:
};
I do remember having read that this would work:
UserDB():_accounts(){}
This should initialize the contents to NULL