Getting rid of ScopedPointer

Custom deleters are also needed for simd aligned memory.

JUCE uses them to automatically release objective-c classes too

I’ve just started going through an old project to clean up ScopedPointer usage. I ended up doing e.g.

addAndMakeVisible ((myMember = std::make_unique<SomeComponent>()).get());

which seems a little more readable.

What about one that takes a const std::unique_ptr <Component>& child ?
That seems to be a way to indicate that the function takes a unique_ptr argument without taking ownership on the object it holds.

I’ve seen that mentioned in a few places on StackOverflow, is there anything said about it by C++ gurus?
@timur, does the C++ committee have a stance on this?

Yes, that’s what I meant - it’d have to be a const reference for it to work. But I still think that’d be quite confusing as a function prototype - I know that if I saw a function that takes any kind of const unique_ptr& then I’d be scratching my head wondering why it was written that way! But yes, it would do the job of solving this use-case

Tangentially to this subject, I’m trying to integrate this support for unique_ptr to Components as arguments in some methods of my code and I have a question:

can you confirm that if I have a:

unique_ptr <juce::TextButton> textButton;

then it will not be matched by the following method signature:

void actOnComponent (const unique_ptr <juce::Component>& c);

because unique_ptr <Component> is not a base class for unique_ptr <TextButton>

and then I have to do it this other way instead?

template <typename ComponentType>
void actOnComponent (const unique_ptr <ComponentType>& c);

do you see any clean way around this, that would allow me to avoid this template trick?

Could you just have your functions take a const Component& argument, and dereference the pointer before calling the function?

Could you just have your functions take a const Component& argument, and dereference the pointer before calling the function?

Yes, but for UI code in particular I value readability of the code, thus I prefer to have clean calls like:

actOnComponent (someButton);

regardless of whether someButton is a reference, pointer, unique_ptr, ScopedPointer or whatever.

Disclaimer: I’m not saying a unique_ptr overload should always be provided where a pointer or a reference already make sense. I’m only asking what is the best way to provide one because, in this particular context, I prefer to have uncluttered widget names as arguments, without sprinlking around ‘*’ or ->get()

Also, having this uniformity in calling those methods, I can more easily transition from say a
std::unique_ptr <TextButton> b
to a simpler
TextButton b
later on.

OT - Any chance we could get all the Tutorials updated to cover this issue? As someone who just started with JUCE, it’s confusing that deprecated methods are used and it doesn’t reflect the current best practices…

I just grep-ped over the JUCE develop branch, and can’t find any occurrence ScopedPointer, only OptionalScopedPointer, which is a different thing (and also not deprecated).

Can you post, where you still see it?

I guess I’m referring to the online Tutorials that instruct you to use ScopedPointer. Such as this one:

https://docs.juce.com/master/tutorial_main_window.html

Ah, I see… sorry :slight_smile:
Hope the JUCE team changes that then…

@yfede Yeah, it’s summarised in the C++ Core Guidelines rules for smart pointers: C++ Core Guidelines: Rules for Smart Pointers – MC++ BLOG

Does this cover your question?

Just an observation that if I was writing addAndMakeVisible today, I’d never have used a pointer, it should have only ever had a Component& parameter.

The object being passed in can’t be nullptr and it’s not taking ownership, so the only reason the function took a pointer was my inexperience when I wrote it back in 2001 or whenever it was!

3 Likes

It does in a way: I think R.30 from that article is the one that covers this case:
R.30: Take smart pointers as parameters only to explicitly express lifetime semantics

From the text that it links to:

Accepting a smart pointer to a widget is wrong if the function just needs the widget itself. It should be able to accept any widget object, not just ones whose lifetimes are managed by a particular kind of smart pointer. A function that does not manipulate lifetime should take raw pointers or references instead

I feel like the reason behind this rule is leaning a little towards the “don’t specialize your method for smart pointers if it works with (non-owning) raw pointers too”, without taking in consideration the readability impact that sprinkling ‘*’ and .get() here and there may have.

However,

I also agree with Jules that in the particular case of methods taking Components as parameters, almost all of them will want the passed arguments to be existing Components rather than null pointers (regardless if raw or smart), therefore a Component& parameter seems the only one that perfectly fits that requirement.

Wow this is some serious programmer humility here. :wink:

Are you saying that the one that takes the raw pointer will be deprecated sooner or later?

Given the thousands of codebases that are crammed with code that uses it, probably not any time soon!

1 Like

ScopedPointer … I don’t suppose there’s likely to be a compiler flag you add to deprecate it ? :slight_smile:

We need to upgrade some projects for Catalina support, and well, one project has 500 separate ScopedPointers that are generating a lot of warnings :slight_smile: