When creating a new project and using “Robot C++ Project” (command-based), the example subsystem is declared as a std::unique_ptr rather than an old-style standard pointer:
Given that the example code is using this pointer type, I figured it was probably a good idea for us to start using it too. Might as well take advantage of the memory-management features that unique_ptr provides.
That was great until we tried to use the subsystem as a Requires() parameter. Requires() only accepts a Subsystem *. You can get around that with unique_ptr’s get() method but the result is a bit messy:
Requires((Subsystem *)(examplesubsystem.get()));
If you use unique_ptr’s across the board, you’ll also run into the same issue with things like joystick buttons and anywhere else where you have to pass in a pointer to an object.
My questions are:
Should we be using std::unique_ptr like the example code is leading us to do?
Is FRC/WPILib moving towards using std::unique_ptr’s?
Will they overload existing methods to accept both types of pointers (old and new)?
Yes WPIlib is moving to using more of the standard library pointer wrappers. I like using them because it makes it way easier to manage the code. Also you don’t have to cast to a subsystem pointer. We do
Requires(Robot::drivebaseSubsystem.get());
And it works fine for us.
I doubt that they will overload the functions to accept both. The whole reason they switched was to make it easier for teams to debug.
Excellent. At least we’re heading in the right direction.
I didn’t realize that I didn’t need the cast. I added it to fix an error but obviously it was some other problem that I was having. I just tried and it works fine without the cast.
Using the get() without all the extra parentheses makes it much more usable.
We also started using smart pointers in WPILib so we could express ownership semantics. As the name implies, std::unique_ptr represents an object with one owner.
Since no one has mentioned this yet, I’ll point out that a raw pointer is the non-owning counterpart of std::unique_ptr (which can be obtained via get()). Given those semantics, Requires() takes a non-owning reference to a subsystem because subsystem lifetime is a strict superset of command lifetime.
By the way, shared ownership is represented by std::shared_ptr and std::weak_ptr for owning and non-owning references respectively.