Search code examples
c++private-members

Vector of class object with private constructor and destructor?


Defining the classes A with private constructor and destructor (it should be so!) and B as a friend class, how can I creat a vector of A objects in B and fill it with the function addA(). I got the error "error C2248: "A::~A": No access to private members whose declaration was made in the A class".

class A
{
private:
    A();
    A(const std::string& name, const float& num);
    ~A();
public:
    friend class B;
private:
    std::string name_;
    float num_;
};

A::A() 
{
    name_ = "NoName";
    num_ = 0.0;
}
A::A(const std::string& name, const float& num)
{
    name_ = name;
    num_ = num;
}
A::~A()
{   
}

class B
{
public:
    B();
    ~B();
    void addA(const std::string name, const float num);
private:
    vector<A> vecA;
};

B::B() 
{
}
B::~B() 
{
}
void B::addA(const std::string name, const float num)
{
    A a(name, num);
    vecA.push_back(a);
}

int main()
{
    B b;
    b.addA("Name", 1.0);

    return 0;
}

Solution

  • how can I create a vector of A objects in B [...] ?

    You can't do that. While B is a friend of A, std::vector is not a friend of A, which means that it cannot access private members of A, e.g., constructor, which is required for a vector to work.

    However, if you are okay with a little indirection, little potential performance hit and a change in your signature, you can replace the not-working std::vector<A> with a workig std::vector<std::unique_ptr<A, deleter>>.

    It's important to note that plain std::unique_ptr will not work here. It has a similar problem to std::vector - it cannot access private destructor of A. One way to work around it is to outsource the job of constructing and destructing of As entirely to B - via explicit construction and destruction, that is:

    • new A(name, num)
    • static void deleter_a(A* a) { delete a; }

    in B's scope.

    Now we can do:

    std::vector<std::unique_ptr<A, std::function<void(A*)>>> vecA;
    

    instead of: std::vector<A> or std::vector<std::unique_ptr<A>>. This is important - neither std::unique_ptr nor std::vector construct or destruct your As. B is entirely responsible for constructing (new A(name, num)) and destructing (static void deleter_a(A* a) { delete a; }) As.

    Full B class:

    class B {
    public:
        B() {};  // or = default
        ~B() {}; // or = default
        void addA(const std::string name, const float num);
    
    private:
        static void deleter_a(A* a) { delete a; }
        using deleter_a_t = void(A*);
        std::vector<std::unique_ptr<A, std::function<deleter_a_t>>> vecA;
    };
    
    void B::addA(const std::string name, const float num) {
        vecA.push_back(std::unique_ptr<A, std::function<deleter_a_t>>{
                new A(name, num), std::function<deleter_a_t>{deleter_a}
        });
    }