How to pass array of MyClass pointers


#1

I’m struggling with creating an OwnedArray or ReferenceCountArray and pass that object as a reference to a function which should assign it to a member variable.

What i would need is (which obviously doesn’t work):

Target.h

private:
    OwnedArray<MyClass> listElements;
public:
    void setListElements(OwnedArray<MyClass>& items);

Target.cpp

void ListComponent::setListElements(OwnedArray<MyClass>& items) 
{
    listElements = items; 
}

Test.cpp

OwnedArray<MyClass> array;
MyClass* el = new MyClass();
el->setName("Hello");
array.add(el);
target.setListElements(array);

So my main question is: How can i achieve it that an array of MyClass pointers can be passed as an array reference to a function in another class and there be assigned to an appropriate member variable in order that the content can be used there for whatever?
Of if that’s not possible at all how can it be done alternatively?


#2

This works for me:

void setGroupArray (OwnedArray<CMidiGroup>* pGroupArray);

What you’re trying to do would need a copy constructor for OwnedArray.

Rail


#3

That works fine, thank you for the tip!
How do you delete that pointer member variable? Using

delete[] myArrayVariable;

in the destructor is not recommended.

EDIT: It worked by declaring the pointer as

ScopedPointer<OwnedArray<MyClass>> listElements;


#4

You don’t delete it in your class – you use

OwnedArray<MyClass>* pListElements;

and the class which calls setListElements() is responsible for the lifetime of the array:

Member variables:

OwnedArray<MyClass>      m_array;   

Implementation:

MyClass myclassVariable;
myclassVariable .setName ("Hello");
MyClass * pEL = m_array.add (myclassVariable);

target.setListElements (&m_array);

// pEL has scope until the next closing brace
//  OwnedArray will create a new MyClass object and delete it when the array goes out of scope

Of course this assumes some things about what you’re trying to do.

Rail


#5

But m_array (in your example) is not a member variable but one which is created inside the method which populates and passes it to the target class, i.e. if that one is destroyed when that function completes i also cannot use it anymore in the target class. Therefore i let the target class decide when to destroy it.

Target.h

private:
    ScopedPointer<OwnedArray<ListElement>> listElements;

Target.cpp

void ListComponent::setListElements(OwnedArray<ListElement>* items)
{
    listElements = items;
}

Source.cpp

OwnedArray<ListElement>* array = new OwnedArray<ListElement>();
ListElement* el = new ListElement();
el->setName("Hello");
array->add(el);
categoryListComponent.setListElements(array);

This works fine, no delete necessary in Source nor Target class. Probably not good coding behaviour.
With any other approach i run into a lot of BAD_ACCESS errors.


#6

Pseudo-code:

Source class :

public:

YourSourceClass::YourSourceClass() {}
YourSourceClass::~YourSourceClass() 
{
    // Set the Target to null just in case -- but m_Target because of the variable 
    // declaration order should be destroyed before m_Array

     m_Target.setListElements (nullptr);

     // The OwnedArray gets destroyed here and deletes all the objects in it.
}

OwnedArray<ListElement>  m_array;   

TargetClass              m_Target;

Implementation:

void YourSourceClass::someMethod()
{
ListElement* pEL = m_array.add (new ListElement());

pEL->setName ("Hello");

m_Target.setListElements (&m_array);

// pEL has scope until the next closing brace
}

Target class

public:

ListComponent:: ListComponent() : m_pArrayFromSource (nullptr)
{
}

OwnedArray<ListElement>* m_pArrayFromSource;

void ListComponent::setListElements (OwnedArray<ListElement>* pItemArray)
{
    m_pArrayFromSource = pItemArray;
}

void ListComponent::someMethod()
{
    if (m_pArrayFromSource != nullptr)
        m_pArrayFromSource->useThePointerToDoSomething();
}

As long as the variable m_array isn’t destroyed before the Target class you can use m_pArrayFromSource

In this example if the Source gets destroyed it sets the Target pointer to null so you can always check if it’s valid before using it.

If your Target class is going to last longer than the source class – then declare m_array as a member of the Target class and get the pointer from the Target in the source class.

From the OwnedArray docs:

An array designed for holding objects.

This holds a list of pointers to objects, and will automatically delete the objects when they are removed from the array, or when the array is itself deleted.

Rail


#7

I see what you’re meaning, but you treat m_array as a member variable in Source class. In my case i have to create, populate and pass several of these arrays in someMethod to the Target class, because they will transport database result sets to different ListComponent objects, for every component i need to create dynamically an array and pass that to the correct ListComponent object (i.e. Target).
In my opinion all of these arrays would be deleted right after someMethod ends and there is my problem :slight_smile:


#8

Well perhaps you need to create temporary arrays in the source class and then append the contents to an array in the Target class… I’ve given you enough info in my previous post to figure out what you need to do for your particular application. Between the post and the OwnedArray docs you should have a fairly good understanding now of the objects’ lifetime and who owns/destroys the objects.

Rail


#9

And i say thank you very much for that, it’s much appreciated :slight_smile:
That is what i actually do now: get the pointer from someMethod and store it in a member variable in Target:

ScopedPointer<OwnedArray> listElements;


#10

Isn’t there a swapWith method? This would allow the initial approach without relying on a copy constructor…


#11

The best practice modern C++ when passing a large object whose ownership will be taken by the receiver is to make the argument a std::unique_ptr (or ScopedPointer, which is basically the same)

void takeArrayOfMyObjects (std::unique_ptr<OwnedArray<MyObject>> thingToTake)

That’s preferred to a raw pointer as it makes it clear to the caller that ownership will be taken. A lot of JUCE code couldn’t be written like that because of a lack of move operators in C++03 but we’ll be drifting over to this style in the future now that we’re all on C++11.


#12

That’s great, thank you all! Then my found solution isn’t that bad at all!