Suppose I have a class with a factory method
class A {
public:
static A* newA()
{
// Some code, logging, ...
return new A();
}
}
Is it possible to prevent the instantiation of an object of this class with a new, so that factory method is the only method to create an instance of the object?
Sure; just make the constructor private (protected if this is a base class):
class A {
public:
static A* newA()
{
// Some code, logging, ...
return new A();
}
private:
A() {} // Default constructor
};
You should make the copy constructor private/protected as well, if required.
And as always, you should strongly consider returning a smart pointer rather than a raw pointer, in order to simplify memory management issues.
You may also want to make the copy constructor private as well or with new C++11 syntax you can explicitly tell the compiler to not copy it and make the default constructor private with something like this:
struct NonCopyable {
NonCopyable & operator=(const NonCopyable&) = delete;
NonCopyable(const NonCopyable&) = delete;
NonCopyable() = default;
};
class A : NonCopyable {
public:
static std::shared_ptr<A> newA()
{
// Some code, logging, ...
return std::make_shared<A>();
}
private:
A() {} // Default constructor
};
The C++03 way was usually something like this:
class A {
public:
static A* newA()
{
// Some code, logging, ...
return new A();
}
private:
A() {} // no outsider default constructor
A(const A& rhs); // no copy
A& operator=(const A& rhs); // no assignment
};
int main()
{
A x; // C2248
A y(x); // C2248
x = y; // C2248
A* p = A::newA(); // OK
std::cin.get();
return 0;
}
Related
Is it possible to do a two-step initialization of a non-movable object in the member initializer list using C++17?
Here is the legacy API I’m working with (and yes I know it’s bad but I can’t change it)
class A {
public:
A(int some_param);
// no default, move or copy constructor nor assignment
A() = delete
A(const& A) = delete;
A(const&&) = delete; // it shouldn’t be deleted, but I’m not able to modify that class
A& operator= (const& A) = delete;
A& operator= (const&&) = delete;
// and it uses two phase construction
void init(int some_other_argument);
// more stuff
};
class B {
public:
// no default constructor, and must be created with a fully-initialized A
B() = delete;
B(const& A);
// more stuff
};
And here is what I am trying to write:
class C {
public:
C();
private:
A m_a;
B m_b;
};
C::C()
: m_a{ /* two step initialization of A*/}
, m_b(m_a)
{}
The usual trick of using a immediately initialize lambda doesn’t work:
C::C()
: m_a{[] {
auto a = A(0xdead_beef);
a.init(42);
return a; // doesn’t compile because A isn’t movable
}()}
, m_b(m_a)
{}
Nor does using the body of the constructor:
C::C()
// m_a and m_b will be default-initialized here, but their default initializer are deleted
{
m_a = A(0xdead_beef);
m_a.init();
m_b = B(m_a);
}
And nor doing the second step of the two step initialization in the body of the constructor:
C::C()
: m_a(0xdead_beef)
, m_b(m_a) // m_a isn’t fully initialized here
{
m_a.init();
}
Currently I’m using a unique_ptr for m_b, but I was asking myself if there was a better solution.
class C {
public:
C();
private:
std::unique_ptr<A> m_a; // guaranted to be initialized in the constructor, no need to check before dereferencing
B m_b;
};
C::C()
: m_a{[] {
auto a = new A(0xdead_beef);
a->init(42);
return a;
}()}
, m_b(*m_a)
{}
I think the rules of guaranteed move elision were improved in C++20, but I’m still using C++17.
You might still abuse of comma operator:
C::C() : m_a{ 0xdeadbeef },
m_b((m_a.init(42), m_a))
{}
Providing the simple implementation of a Singleton class below. It is possible for anybody to call the destructor as long as s/he has the reference to the singleInstance.
class SomeClass {
public: /** Singleton **/
static SomeClass &instance() {
static SomeClass singleInstance;
return singleInstance;
};
private:
SomeClass() = default;
SomeClass(const SomeClass&) = delete;
SomeClass &operator=(const SomeClass&) = delete;
};
To prevent such a nonsense operation, should we declare the destructor of Singleton classes in a private context?
class SomeClass {
// ... same above
private:
~SomeClass() {}
};
The problem exists also for the heap-allocated Singleton instances. Consider the implementation below.
class SomeClass {
public: /** Singleton **/
static SomeClass &instance() {
static SomeClass *singleInstance = nullptr;
if(!singleInstance) {
singleInstance = new SomeClass;
}
return *singleInstance;
};
private:
SomeClass() = default;
SomeClass(const SomeClass&) = delete;
SomeClass &operator=(const SomeClass&) = delete;
// ~SomeClass() {}
};
int main()
{
SomeClass *const ptr = &SomeClass::instance();
delete ptr; // Compiles if destructor isn't private and vice versa
return 0;
}
Should we declare the desctructor of a Singleton class as private?
Yes.
Sidenote: Singleton pattern is rarely necessary, an using it unnecessarily is a common anti pattern.
Assume a C++ class A with members that can all be copied by the their respective copy constructors. We can rely on the default copy constructor for A to copy its members:
class A {
private:
A(const A&) = default; // We don't really need this line
int a;
B b;
double c;
}
But now let's assume that I want to "extend" (or annotate) the default constructor of A so that in addition to copying its members, it does something else, e.g. writes a line to a log file.
I.e. I'd like to write something like:
class A {
public:
A(const A& a) : A::default(A) {
print("Constructing A\n");
}
private:
// like before
}
Unfortunately that is not correct C++ syntax.
So is there a syntax which allows delegating to a default C++ constructor while explicitly defining the same constructor?
The simplest is to move all members into a base class and write the message in a derived class:
class A_helper {
private:
int a;
B b;
double c;
};
class A : public A_helper {
public:
A() = default;
A(const A& a) : A_helper(a) {
print("Constructing A\n");
}
A(A&& a) : A_helper(std::move(a)) {
print("Constructing A\n");
}
};
You can delegate to the default constructor like you would default-initialize a member variable:
A(const A&) : A()
{
...
}
As often, "We can solve any problem by introducing an extra level of indirection." ( "…except for the problem of too many levels of indirection,"):
struct VerboseA
{
VerboseA() = default;
VerboseA(const VerboseA&) { print("Constructing A\n"); }
VerboseA(VerboseA&&) { print("Constructing A\n"); }
};
And then
class A : VerboseA // EBO (Empty Base Optimisation)
{
private:
A(const A&) = default; // We don't really need this line
int a;
B b;
double c;
};
or in C++20
class A {
private:
A(const A&) = default; // We don't really need this line
[[no_unique_address]]VerboseA verbose; // "EBO" equivalent with attribute
int a;
B b;
double c;
};
I have two classes:
class NonCopyable {
private:
int key;
protected:
NonCopyable(const NonCopyable&) = delete;
NonCopyable& operator = (const NonCopyable &) = delete;
};
class Derived : public NonCopyable {
private:
std::vector<int> numbers;
float f;
int* ptr;
public:
Derived() : f(5.0f), ptr(nullptr) {}
~Derived();
};
Now, I'd like to reinitialize all the values in the Derived class and call the appropriate destructors. That is, the NonCopyable class should not be touched, but the Derived class should be changed as if it was newly initialized.
What is the simplest way of achieving this goal? I am trying to avoid making a member function which manually reinitializes every member variable.
Clearly, I can not use the following approach:
Derived d;
// [...] many changes to d
d = Derived();
because the copy constructor is deleted from the NonCopyable class and the fact that it would change the member variables of NonCopyable had this not been the case.
It becomes much easier if you move your private data to a separate aggregate:
struct DerivedData {
std::vector<int> numbers;
float f = 5.0;
int* ptr = nullptr;
};
class Derived : public NonCopyable {
DerivedData data;
public:
~Derived();
void reset() { data = DerivedData(); }
};
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;
};