Search code examples
armunique-ptr

Error using unique pointer from interface as attribute of a class


In a nutshell, I need help with the right use of unique_ptr and not with the library ArmNN. So, the next paragraph is just for contextualization.

I am adapting my current application to use the library ArmNN. More specifically, I am doing that through the use of the interface ICaffeParser.

At line 22 of this interface, we have this using definition to define a unique_ptr to the interface, that I believe is the "cause" of my problems.

using ICaffeParserPtr = std::unique_ptr<ICaffeParser, void(*)(ICaffeParser* parser)>;

I am quite sure my problem is the incorrect use of unique_ptr in my context, once I could make some successful tests with a more simple application.

My current code contains a class, let's call it MyClass:

namespace MYNAMESPACE {
    class MyClass {
        public:
            MyClass() {
            }
            // a lot of functions
            // a lot of attributes
        private:
            // a lot of functions
            // a lot of attributes
    }
}

In order to make use of the ArmNN library, I have created a new private attribute for MyClass:

armnnCaffeParser::ICaffeParserPtr myParser;

and instantiated myParser at MyClass() constructor:

MyClass::MyClass() {
    myParser = armnnCaffeParser::ICaffeParser::Create();
}

Remembering ICaffeParserPtr is a unique_ptr (I think), now I have the following compiling error:

/my_path/src/detector.cpp: In constructor ‘MYNAMESPACE::MyClass::MyClass()’:
/my_path/src/detector.cpp:13:20: error: no matching function for call to ‘std::unique_ptr<armnnCaffeParser::ICaffeParser, void (*)(armnnCaffeParser::ICaffeParser*)>::unique_ptr()’
MyClass::MyClass() {
                 ^
In file included from /usr/aarch64-linux-gnu/include/c++/7/bits/locale_conv.h:41:0,
             from /usr/aarch64-linux-gnu/include/c++/7/locale:43,
             from /usr/aarch64-linux-gnu/include/c++/7/iomanip:43,
             from /usr/include/opencv2/flann/lsh_table.h:40,
             from /usr/include/opencv2/flann/lsh_index.h:49,
             from /usr/include/opencv2/flann/all_indices.h:42,
             from /usr/include/opencv2/flann/flann_base.hpp:43,
             from /usr/include/opencv2/flann.hpp:48,
             from /usr/include/opencv2/opencv.hpp:62,
             from /my_path/src/detector.hpp:11,
             from /my_path/src/detector.cpp:1:
/usr/aarch64-linux-gnu/include/c++/7/bits/unique_ptr.h:255:2: note: candidate: template<class _Up, class> std::unique_ptr<_Tp, _Dp>::unique_ptr(std::auto_ptr<_Up>&&)
unique_ptr(auto_ptr<_Up>&& __u) noexcept;

/usr/aarch64-linux-gnu/include/c++/7/bits/unique_ptr.h:255:2: note:   template argument deduction/substitution failed:
/my_path/src/detector.cpp:13:20: note:   candidate expects 1 argument, 0 provided
 MyClass::MyClass() {
                  ^

Solution

  • The error happens because myParser is actually being default-initialized and then assigned on the constructor body of MyClass::MyClass().

    Since a function pointer is passed as a custom deleter to std::unique_ptr to form the ICaffeParserPtr type, the default constructor for this particular instance of std::unique_ptr is disabled as per [unique.ptr.single.ctor].

    In other words, ICaffeParserPtr, for safety reasons, cannot be default-initialized — which specific function to otherwise assign as its deleter on initialization?

    To address this, you should always initialize class members at the member initializer list. In this case, initialize myParser as such:

    MyClass::MyClass():
      myParser(armnnCaffeParser::ICaffeParser::Create()) {}
    

    This avoids calling the unavailable default constructor for std::unique_ptr, and is generally a better practice than assigning to class members in the constructor body.