I am trying to use a smart pointer class in the following way
class A
{
friend class B;
virtual methods ();
protected:
virtual ~classA();
}
class B:public QSharedPointer<class A>
{
class B();
~ class B();
}
I plan to replace occurrences of Class A* with class B. Is this approach correct?
No this is not really the way to do this. It looks like your design goal here is to make it impossible for someone to allocate an object of type A without putting it in a smart pointer. The normal way to do this is not to inherit from the smart pointer, but to make your type have
A private constructor
A private destructor
A public static factory method returning in this case QSharedPointer
A private deleter class that is a friend of class A
Here is an example using boost::shared_ptr (I do not have a QT installation right now, but you should be able to just replace all instances of boost::shared_ptr with QSharedPointer)
#include <boost/shared_ptr.hpp>
class A {
private:
A() {}
~A() {}
struct deleter {
void operator()(A* val) {delete val;}
};
friend class deleter;
public:
static boost::shared_ptr<A> create() {
return boost::shared_ptr<A>(new A(), A::deleter());
}
};
int main()
{
//A a1; //compile error
//A *a2 = new A(); //compile error
boost::shared_ptr<A> a3 = A::create();
return 0;
}
Related
i am new to shared pointers. I would like to have a method which returns reference to an object. The object will be created inside a method by make_shared and also stored in a vector as a shared pointer of base class. I guess my code is not the best way to do it. Any suggestions?
Thank you.
class A {
public:
};
class B : public A {
public:
};
class Factory {
public:
B& createA() {
std::shared_ptr<B> b = std::make_shared<B>();
container.push_back(b);
return *b;
}
private:
std::vector<std::shared_ptr<A>> container;
};
int main() {
Factory factory;
B& b = factory.createA();
// work with B here...
}
Suppose I have a class like the following:
class A { virtual ~A(); ... }
class B : public A { ... }
class C : public A { ... }
I also have a vector of unique_ptr which is declared this way:
std::vector<std::unique_ptr<A>> vec;
Assume vec is populated with unique_ptr to objects of derived class. What should I do if I want a deep copy of any of the vector elements, either b or c, and let a base class unique_ptr pointing to it? Originally I was doing things like
std::unique_ptr<A> tmp = std::make_unique<A>(*b);
I don't think this is correct.
One possible solution is to declare a virtual cloning method in the base class and override it for each subclass:
class A {
virtual ~A() {}
virtual std::unique_ptr<A> clone() const = 0;
}
class B : public A {
std::unique_ptr<A> clone() const override {
return std::unique_ptr<A>(new B(*this));
}
};
Edit:
An usage example:
void f(const A& original) {
std::unique_ptr<A> copy = original.clone();
// Here, copy points to an instance of class B.
}
Say I have a class:
class Foo{
public:
Foo(){
}
//Is it possible to create a function like this:
virtual Foo* createOb(){
//Should create a new Foo,Bar or Fiz, depending on the actual object type.
}
}
class Bar: public Foo{
public:
Bar(){
}
}
class Fiz: public Foo{
public:
Fiz(){
}
}
Is it possible to have a method createOb() in the base class, so when createOb() is called on an instance of one of the derived classes, that an instance of the derived class is created ?
Yes, it can be done, using CRTP.
Bu first, returning a raw pointer obtained from new is very dangerous. In c++ raw pointers should be used only when they do not have ownership of the pointed object. So I took the liberty to use unique_ptr:
struct Base {
virtual auto create_obj() -> std::unique_ptr<Base>
{
return std::unique_ptr<Base>{};
}
};
// abstract works too:
struct Base {
virtual auto create_obj() -> std::unique_ptr<Base> = 0;
};
template <class Derived>
struct Base_crtp : Base {
auto create_obj() -> std::unique_ptr<Base> override /* final */
{
return std::unique_ptr<Base>{new Derived{}};
}
};
struct D1 : Base_crtp<D1>
{
};
struct D2 : Base_crtp<D2>
{
};
And then:
auto b1 = std::unique_ptr<Base>{new D1{}};
auto b2 = std::unique_ptr<Base>{new D2{}};
auto new_d1 = b1->create_obj();
auto new_d2 = b2->create_obj();
Definitely YES!!!
When a method is declared virtual in base class, and called through the derived class object, then the derived class function gets called (Read vprt, vtable concept in c++).
#include <iostream>
using namespace std;
class A{
public:
virtual A* getobj(){
return new A();
}
};
class B: public A{
public:
B(){cout<<"B constructor"<<endl;}
virtual A* getobj(){
return new B();
}
};
int main()
{
A *a = new B();
A *second = a->getobj();
return 0;
}
In the above code, we are calling the getobj() function using class B's object.
Here the constructor of class B is called twice.
first, for new B() in main
secondly for getobj function call which again creates object of B
This is not an optimal solution, but it works.
In your .h
class Foo{
public:
Foo();
virtual Foo* createOb();
};
class Bar: public Foo{
public:
Bar();
};
class Fiz: public Foo{
public:
Fiz();
};
In your .cpp
#include "Header.h"
Foo::Foo() {}
Foo* Foo::createOb(){
if (dynamic_cast<Bar*>(this)) {
return new Bar();
}
else if (dynamic_cast<Foo*>(this)) {
return new Foo();
}
return nullptr;
}
Bar::Bar() {}
Fiz::Fiz() {}
As already suggested please consider a pure virtual method
No, this is not possible with "pure" inheritance. The classes must override createOb() member function in order to support cloning.
You can see why this is not possible by considering separate compilation of classes. An implementation of one-fits-all createOb() member function must be completed in isolation from Bar and Fiz, making it impossible for the base to know the type of its subclasses.
An implementation with a pure virtual function in the base is very common, though.
Another approach is to use Curiously Recurring Template Pattern (CRTP) to implement cloning. This article explains how it can be done.
I have strange assertion error and I can not find what is wrong with this code.
Assertion expression is _BLOCK_TYPE_IS_VALID(pHead->nBlockUse).
I simplified code a bit for better readability.
class Creator
{
public:
virtual ~Creator()
{
for (MyObject* item : _list)
{
delete item; <-- assertion error here
item = 0;
}
_list.clear();
}
template <class T>
T& create()
{
T * item = new T();
_list.push_back(item);
return *item;
}
private:
std::list<MyObject*> _list;
};
class A : public MyObject, public Creator
{
};
class B : public MyObject, public Creator
{
};
int main()
{
A a;
a.create<A>();
} <-- call of destructor
The idea is that an object witch inherits Creator, can create any other object, and hold pointers to those objects. While programmer can work with references. And when "super" object is destroyed, all "sub" objects are destroyed too.
Program works like a charm if I change to:
template <class T>
class Creator
{
public:
virtual ~Creator()
{
for (T* item : _list)
{
delete item;
item = 0;
}
_list.clear();
}
T& create()
{
T * item = new T();
_list.push_back(item);
return *item;
}
private:
std::list<T*> _list;
};
class A : public MyObject, public Creator<A>
{
};
class B : public MyObject, public Creator<B>
{
};
int main()
{
A a;
a.create();
}
Now create method creates only one type of object ( object A in this example ).
But I need, that create method could create any object that inherits MyObject. Like in first peace of code.
Any help for this assertion error would be appreciated. Thanks.
The issue is that your MyObject class lacks a virtual destructor, and you're attempting to call delete on a pointer to the derived class using a pointer to the base class MyObject. Issuing a delete on a derived object through a base class pointer is undefined behavior if the base class destructor is not virtual.
5.3.5 Delete (Paragraph 3)
In the first alternative (delete object), if the static type of the
operand is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual destructor or the behavior is undefined.
Once the destructor is made virtual in the base class MyClass, the following works correctly in Visual Studio 2013:
#include <list>
struct MyObject
{
virtual ~MyObject() {}
};
class Creator
{
public:
virtual ~Creator()
{
for (MyObject* item : _list)
{
delete item;
item = 0;
}
_list.clear();
}
template <class T>
T& create()
{
T * item = new T();
_list.push_back(item);
return *item;
}
private:
std::list<MyObject*> _list;
};
class A : public MyObject, public Creator
{
};
class B : public MyObject, public Creator
{
};
int main()
{
A a;
a.create<A>();
}
Problem is that you try to delete A object via MyObject pointer and MyObject destructor is not virtual. You could make MyObject's destructor virtual and then you can delete subclasses objects via pointer to MyObject. For more details on this issue see this question
I think the issue is with multiple inheritance. Here's a simplified way to reproduce the problem.
It can be fixed by
casting it to the most derived type OR
having the destructor of the base class be virtual.
In your case, the virtual function approach is best as it is recommended to have base class destructor(s) to be virtual to get the destruction calls through the inheritance hierarchy.
class A
{
};
class B
{
};
class C : public A, public B
{
};
int main()
{
// Fails with memory heap error
B* pB = new C();
delete pB;
}
To fix it
int main()
{
B* pB = new C();
// Casting it to the "full" type will fix it
C* pC = static_cast<C*>(pB);
delete pC;
}
The second program works because it is similar to this below.
int main()
{
// Pointer to the "full" type works
C* pC = new C();
delete pC;
}
Forgive me if this has already been asked, I didn't find any answers to my specific question.
I have a class in a library I'm making that I want certain classes to be able to create and destroy, and other classes to be able to access other public functions. Having a friend class is not what I want either as the friend class will get access to member variables and member functions which I don't want. I stumbled upon this idiom which almost works, except for the destructor since it can't take additional parameters. With that idiom, I get:
class B;
class A
{
public:
class LifecycleKey
{
private:
LifecycleKey() {}
friend class B;
};
A(LifecycleKey); // Now only class B can call this
// Other public functions
private:
~A(); // But how can I get class B to have access to this?
void somePrivateFunction();
// Members and other private functions
};
As alluded to in the above code, the solution doesn't allow only class B to have access to the destructor.
While none of the above issues are deal breakers by any stretch as I can always just make ctor and dtor public and just say "RTFM".
My question is:
Is there is some way to limit access to ctor and dtor to specific classes (but only the ctor and dtor) while adhering to more well known syntax (having stuff be on the stack if people want, destroying via delete , etc.)?
Any help is greatly appreciated!
SOLUTION
in A.h
class B;
class A
{
protected:
A() {}
virtual ~A() {}
A(const A&); // Implement if needed
A(A&&); // Implement if needed
public:
// Public functions
private:
void somePrivateFunction();
// Members and other private functions
};
in B.h
class B
{
public:
B();
~B();
const A* getA() const;
private:
A* m_a;
}
in B.cpp
namespace {
class DeletableA : public A {
public:
DeletableA() : A() {}
DeletableA(const DeletableA&); // Implement if needed
DeletableA(DeletableA&&); // Implement if needed
~DeletableA() {}
}
}
#include B.h
B::B() : m_a(new DeletableA()) {}
B::~B() { delete static_cast<DeletableA*>(m_a); }
const A* B::getA() const { return m_a; }
Alternatively, if the DeletableA class is needed in B.h or A.h (due to inlining, templating, or desire to have all class A related classes in A.h), it can be moved there with a "pass key" on the constructor so no other classes can create one. Even though the destructor will be exposed, no other class will ever get a DeletableA to delete.
Obviously this solution requires that class B know to make instances of Deletable A (or to make the class in general if it isn't exposed in A.h) and only store A* that are exposed via public functions, but, it is the most flexible set up that was suggested.
While still possible for some other class to make a subclass of class A (since class A isn't "final"), you can add another "pass key" to the constructor of A to prevent such behavior if you wish.
For the goal that class B should be the only one able to instantiate and destroy objects of class A:
For static and automatic variable, restricting access to the constructor is all that's needed, and you're already doing that.
For dynamically allocated object you can restrict access to its deallocation functions, operator delete, and operator delete[], and leave the destructor public. This prohibits other code than B from deleting objects.
For dynamically objects you can derive class A from an interface with protected virtual destructor or named self-destroy function, which has class B as friend. B can then destroy any dynamic A object by casting up to the interface that it has access to.
Code that explicitly calls the destructor deserves whatever it gets.
Remember, you're never building an impregnable defense against malicious code, you're just building a reasonable detection and compile time reporting of inadvertent incorrect use.
Use a mediator-class:
class mediator;
class A
{
/* Only for B via mediator */
A();
~A(); // But how can I get class B to have access to this?
friend class mediator;
/* Past this line the official interface */
public:
void somePrivateFunction();
protected:
private:
};
class B;
class mediator
{
static A* createA() { return new A{}; }
static void destroyA(const A* p) { delete p; }
// Add additional creators and such here
friend class B;
};
Thus, only the mediator, as part of the interface to B, gets full access.
BTW: Instead of restricting access to the dtor, you might get happier overloading new and delete and restricting access to them.
The advantage: Allocation on the stack is generally possible, if the variable is directly initialized without copying.
void* operator new(std::size_t);
void* operator new[](std::size_t);
void operator delete(void*);
void operator delete[](void*);
void operator delete(void*, std::size_t) noexcept;
void operator delete[](void*, std::size_t) noexcept;
use shared_ptr
class K{
public:
int x;
private:
~K(){};
K(){};
private:
friend class K_Creater;
friend class K_Deleter;
};
struct K_Deleter{ void operator()(K* p) { delete p; } };
struct K_Creater{
static shared_ptr<K> Create(){
return shared_ptr<K>(new K, K_Deleter() );
}
};
//K* p = new K; prohibited
shared_ptr<K> p = K_Creator::Create();
another answer is:
#include <iostream>
class A
{
public:
class Key
{
private:
Key(){
std::cout << "Key()" << std::endl;
}
~Key(){
std::cout << "~Key()" << std::endl;
}
friend class B;
};
A(Key key){
std::cout << "A(Key key)" << std::endl;
}
void seti(){ i_=0;}
private:
int i_;
};
class B{
public:
static void foo(){
A a{A::Key()};
A* pa = new A( A::Key() );
delete pa;
static A sa({});
}
};
int main(){
B::foo();
//A a{A::Key()}; prohibit
//A* pa = new A( A::Key() ); prohibit
//delete pa; prohibit
//static A sa({}); prohibit
return 0;
}
My take:
Any class/function that has access to the constructor should also have access to the destructor.
You should make ~A() public since A() is public. Since no other client except B can use the constructor, they won't have the need to use the destructor anyway.
You can further limit who can access the destructor by declaring away the copy and move constructors, and the new and delete operators.
Update
Making the destructor public and declaring away the copy and move constructors seems to address all of your concerns. You don't even need to declare away the new and delete operators or their array variants.
Here's what I think should meet most of your needs.
class B;
class PassKey
{
private:
PassKey() {}
~PassKey() {}
friend class B;
};
class A
{
public:
A(PassKey) {}
~A() {}
private:
// Declare away
A(A const&);
A(A&&);
};
Now, let's take a look at what B can have:
class B
{
public:
B() : a(PassKey()), ap(new A(PassKey())), ap2(new A(PassKey())) {}
~B() { delete ap; }
A const& getA() const {return a;}
A a;
A* ap;
std::shared_ptr<A> ap2;
};
It can have the following member data types:
Objects of type A.
Raw pointers to objects of type A.
Objects of type shared_ptr<A>.
Member functions of B can also create any of the above types of objects.
Other classes can't use objects of type A since they cannot construct one in any way. All the following attempts to use A in various forms fail.
struct C
{
C() : a(PassKey()) {} // Can't construct an instance of A
// since C doesn't have access to
// PassKey's constructor.
A a;
};
struct D
{
D() : a(new A(PassKey())) {} // Can't construct an instance of A
// since D doesn't have access to
// PassKey's constructor.
A* a;
};
struct E
{
E(A const& a) : ap(new A(a)) {} // Can't construct an instance of A
// since E doesn't have access to
// A's copy constructor.
A* ap;
};
class F
{
public:
F(A& a) : ap(new A(std::move(a))) {} // Can't construct an instance of A
// since F doesn't have access to
// A's move constructor.
A* ap;
};