Search code examples
c++visual-studio-2017stdvectorunique-ptrfriend

Iterating through vector of unique_ptr of a struct with private destructor, by a friend, fails in VS 2017


This might be a question with simple answer, but I tried every solution offered by google results, yet unable to fix this in VS 2017.I have a struct B with private destructor. I have another struct A that is friend of struct B, and trying to iterate through the vector of unique pointers to struct B. but I keep getting this error:

Severity Code Description Project File Line Suppression State Error C2248 'ProjectNamespace::NwSpec::~NwSpec': cannot access private member declared in class 'ProjectNamespace::NwSpec' TestProject c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\memory 2055

Any pointers will be greatly appreciated. Thanks.

        struct A
        {
        //functions
        std::vector<std::unique_ptr<NwSpec>> List;
        bool function()const;
        };

        struct NwSpec
        {
            char* Path;//Assume Path is initialized and set with a string.

            private:
                ~NwSpec();

            friend struct A;
        };

        bool A::function()const 
        {
            for (uint32_t i = 0 ; i < List.size(); i++)
            {

            OutputDebugStringA(List[i]->Path);// Error C2248
            }
            // I used iterator to the vector, but getting same error.
            // I used for(const auto& k : List) but getting same access error.
            // NwSpec is visible to A and within ProjectNamespace
        }

Solution

  • You need to create a specialized type responsible for the deletion of the NwSpec object, and provide that to the std::unique_ptr:

    struct NwSpec;
    
    struct A {
    private:
        struct NwSpecDeleter {
            //Note that we're only declaring the function, and not defining it
            void operator()(NwSpec * ptr) const;
        };
    public:
        typedef std::unique_ptr<NwSpec, NwSpecDeleter> ptr_type;
        std::vector<ptr_type> List;
        bool function()const;
    };
    
    struct NwSpec {
        char* Path;//Assume Path is initialized and set with a string.
    
    private:
        ~NwSpec();
    
        friend struct A;
    };
    
    NwSpec::~NwSpec() {}
    
    void A::NwSpecDeleter::operator()(NwSpec * ptr) const {
        delete ptr;
    }
    
    int main() {
        A a;
        a.List.emplace_back(new NwSpec());
        auto ptr = a.List.back().release();
        //This will not compile, as intended
        //delete ptr;
        //Nor will this:
        //ptr->~NwSpec();
        //But this will compile, because the original unique_ptr is perfectly capable of deleting objects:
        a.List.back().reset(ptr);
        a.List.back().reset();//Object is successfully deleted
    
        a.List.erase(a.List.begin(), a.List.end());
        a.List.emplace_back(new NwSpec());
        //This also compiles
        a.List.erase(a.List.begin(), a.List.end());
        return 0;
    }
    

    This code can be tested here.