I want to enforce shared_ptr for a few classes. I'm using a static factory function to encapsulating private constructors:
#include <memory>
class MyClass
{
public:
static std::shared_ptr<MyClass> create() {
auto a = std::shared_ptr<MyClass>(new MyClass());
return a;
}
private:
MyClass();
~MyClass();
}
}
This template fails with C2440, (function-style cast) in VS2017, but works fine in VS2015 and I have no idea why. A make_shared-version works fine in both but requires public constructors.
Any idea which option I'm missing?
Looks like VS2017 complains about accessing destructor from std::shared_ptr, so you may want to declare std::shared_ptr as friend of MyClass. For std::make_shared you can use a trick from this answer How do I call ::std::make_shared on a class with only protected or private constructors?
class MyClass
{
public:
static std::shared_ptr<MyClass> create() {
struct make_shared_enabler : MyClass {};
return std::make_shared<make_shared_enabler>();
}
// compiles fine for gcc without friend though
//friend class std::shared_ptr<MyClass>;
private:
MyClass() {}
~MyClass() {}
};
live example
In addition to other answers: if you don't want to declare std::shared_ptr as a friend of your class and you don't want to make your destructor public, you can create a shared_ptr with the custom deleter. For that you will need some method from your MyClass that can access the private destructor and call delete. For example:
class MyClass
{
public:
static std::shared_ptr<MyClass> create() {
auto a = std::shared_ptr<MyClass>(new MyClass(),
[](MyClass* ptr) { destroy(ptr); });
return a;
}
static void destroy(MyClass* ptr) { delete ptr; }
private:
MyClass(){}
~MyClass(){}
};
// later in the source code
auto ptr = MyClass::create();
You can also declare destroy method as non-static and commit a suicide inside (one of a few situations when it actually makes sense).
Related
I want to call a constructor of a member object in the owners constructor, but can not construct the member object in the initializer-list because of dependencies. How can I call the constructer after my initializations? I would really like to not use an init method
No.
You cannot call the constructor of a member class outside the initializer list.
PS: Even if you don't call it yourself in the initializer list, then the compiler will do it implicitly.
If you cannot call it in the initializer list, and you don't want to use an init-like method, then re-think your design/approach.
You have two options: either use dynamic storage, or placement new.
The first one is obvious (as pointed out in comments, you can use unique_ptr). If you want to avoid this, you might try placement new with std::aligned_union as storage:
class SomeClass { ... };
class Owner
{
public:
Owner()
{
m_ptr = new(&m_storage) SomeClass();
}
~Owner()
{
m_ptr->~SomeClass();
}
private:
std::aligned_union<0, SomeClass> m_storage;
SomeClass* m_ptr;
};
Note: in this case, you are responsible to calling destructor of the object, as shown above.
You can wrap m_ptr with a unique_ptr (with a deleted which only calls a destructor) to avoid this:
struct DtorDeleter
{
template<typename T>
void operator ()(T* ptr) { ptr->~T(); }
};
std::unique_ptr<SomeClass, DtorDeleter> m_ptr; // no need to call destructor manually
You can use an union for this (C++11 needed):
#include <new>
class Foo {
public:
Foo(int a) { }
};
class Bar {
public:
Bar() {
new(&m_foo) Foo(42); // call the constructor
// you can use m_foo from this point
}
~Bar() {
m_foo.~Foo(); // call the destructor
}
private:
union { // anonymous union
Foo m_foo;
};
};
Note that you need to explicitly call the destructor of m_foo at ~Bar().
want to call a constructor of a member object in the owners constructor, but can not construct the member object in the initializer-list because of dependencies
You might modify your class to have correct dependency order, and maybe use delegating constructor:
So turning:
struct S
{
S(/*..*/) : /*m1(data), m2(data),*/ data(/*..*/) // Issue, m1, m2 constructed before data
{
ComplexData2 data2 = Query();
m1.init(data, data2.someField1); // Doesn't like init method
m2.init(data, data2.someField2); // Doesn't like init method
}
Member1 m1; // Cannot be const with init method :/
Member2 m2; // Cannot be const with init method :/
ComplexData data;
};
into
struct S
{
S(/*..*/) : S(Query() /*, ..*/) {}
// private: // probably private
S(const ComplexData2& data2 /*, ..*/) :
data(/*..*/),
m1(data, data2.someField1),
m2(data, data2.someField2)
{
}
public:
ComplexData data; // Before m1, m2 for dependencies.
/*const*/ Member1 m1; // Can be const
/*const*/ Member2 m2; // Can be const
};
I have a class called classA, something like this:
class classA {
private:
char* data;
public:
classA(const classA&) = delete;
~classA();
};
~classA()
{
delete[] data;
}
In another class, let's call it classB, I have as a member a shared pointer to classA:
class classB
{
private:
std::shared_ptr<classA> ptrA;
public:
classB(std::shared_ptr<classA>);
};
classB(std::shared_ptr<classA> sp) : ptrA(sp)
{}
This is how I instantiate my classB:
classA ca;
classB cb(std::make_shared<classA>(ca));
This gives me the following error:
attempting to reference a deleted function
Obviously, I am trying to reference the copy constructor, which I defined as deleted (there is a reason for this, objects of this class shouldn't be copied). But I am confused as to why the copy constructor is called since I am passing a shared pointer, and how to avoid this.
You're calling the copy constructor trying to make the shared pointer.
std::make_shared<classA>(ca)
^^ constructs the classA using these parameters
You can call make_shared<classA>() to create a shared pointer to a default constructed classA. Or chose another constructor.
This example can be simplified quite a bit.
#include <memory>
class classA {
public:
classA(const classA&) = delete;
classA() = default;
};
int main() {
classA ca; // note, no ()
auto sp = std::make_shared<classA>(ca); // problem.
auto sp2 = std::make_shared<classA>(); // this does what you want
}
You are passing ca as an argument to std::make_shared, which constructs a classA by calling classA::classA with whatever arguments that you passed to make_shared.
This might be more obvious if you consider how a make_shared might be implemented.
template <typename Cls, typename... Args>
std::shared_ptr<Cls> MakeShared(Args&&... args) {
//this is where the copying happens
return std::shared_ptr<Cls>{new Cls{std::forward<Args>(args)...}};
}
int main() {
classA ca;
auto sp = MakeShared<classA>(ca);
auto sp2 = MakeShared<classA>();
}
You pass ca to MakeShared, which then calls new Cls(...) where the ... is whatever you passed to MakeShared, in this case, another classA object.
If the above is too dense (maybe you aren't used to forward or variadic templates), then consider this simplified version of MakeShared which does the same thing for your problem case
template <typename Cls, typename Arg>
std::shared_ptr<Cls> MakeShared(const Arg& arg) {
// copy here ----+
// v
return std::shared_ptr<Cls>{new Cls{arg}};
}
int main() {
classA ca;
auto sp = MakeShared<classA>(ca);
}
For a debug situation I need to implement an own version of the shared_ptr class. Typical when I use std::shared_ptr I use a typedef for convenience:
typedef std::shared_ptr<myclass> myclassptr;
in a debug situation I want to extend the shared_ptr template, not the class myclass, with some additional debug methods instead of using the typedef:
class myclassptr : public std::shared_ptr<myclass>
{
public:
// some special tracking methodes
};
but that leave me with a cast at, which does not compile:
myclassptr mcp=std::make_shared<myclass>();
I already encapsulate the make_shared in a factory funktion like:
myclassptr createMyClass()
{
return std::make_shared<myclass>();
}
but how can I get to my debug version?
Give myclassptr a constructor (and probably assignment operator too) which accepts a std::shared_ptr:
class myclassptr : public std::shared_ptr<myclass>
{
public:
// some special tracking methodes
myclassptr(std::shared_ptr<myclass> arg)
: std::shared_ptr<myclass>(std::move(arg))
{}
myclassptr& operator= (std::shared_ptr<myclass> src)
{
std::shared_ptr<myclass>::operator=(std::move(src));
return *this;
}
};
Depending on how you use myclassptr, you may or may not want to mark the constructor as explicit.
In C++, I want to define an object as a member of a class like this:
Object myObject;
However doing this will try to call it's parameterless constructor, which doesn't exist. However I need the constructor to be called after the containing class has done some initialising. Something like this.
class Program
{
public:
Object myObject; //Should not try to call the constructor or do any initializing
Program()
{
...
//Now call the constructor
myObject = Object(...);
}
}
Store a pointer to an Object rather than an actual Object
thus:
class Program
{
public:
Object* myObject; // Will not try to call the constructor or do any initializing
Program()
{
//Do initialization
myObject = new Object(...); // Initialised now
}
}
Don't forget to delete it in the destructor. Modern C++ helps you there, in that you could use an auto_ptr shared_ptr rather than a raw memory pointer.
Others have posted solutions using raw pointers, but a smart pointer would be a better idea:
class MyClass {
std::unique_ptr<Object> pObj;
// use boost::scoped_ptr for older compilers; std::unique_ptr is a C++0x feature
public:
MyClass() {
// ...
pObj.reset(new Object(...));
pObj->foo();
}
// Don't need a destructor
};
This avoids the need to add a destructor, and implicitly forbids copying (unless you write your own operator= and MyClass(const MyClass &).
If you want to avoid a separate heap allocation, this can be done with boost's aligned_storage and placement new. Untested:
template<typename T>
class DelayedAlloc : boost::noncopyable {
boost::aligned_storage<sizeof(T)> storage;
bool valid;
public:
T &get() { assert(valid); return *(T *)storage.address(); }
const T &get() const { assert(valid); return *(const T *)storage.address(); }
DelayedAlloc() { valid = false; }
// Note: Variadic templates require C++0x support
template<typename Args...>
void construct(Args&&... args)
{
assert(!valid);
new(storage.address()) T(std::forward<Args>(args)...);
valid = true;
}
void destruct() {
assert(valid);
valid = false;
get().~T();
}
~DelayedAlloc() { if (valid) destruct(); }
};
class MyClass {
DelayedAlloc<Object> obj;
public:
MyClass() {
// ...
obj.construct(...);
obj.get().foo();
}
}
Or, if Object is copyable (or movable), you can use boost::optional:
class MyClass {
boost::optional<Object> obj;
public:
MyClass() {
// ...
obj = Object(...);
obj->foo();
}
};
You can fully control the object construction and destruction by this trick:
template<typename T>
struct DefferedObject
{
DefferedObject(){}
~DefferedObject(){ value.~T(); }
template<typename...TArgs>
void Construct(TArgs&&...args)
{
new (&value) T(std::forward<TArgs>(args)...);
}
public:
union
{
T value;
};
};
Apply on your sample:
class Program
{
public:
DefferedObject<Object> myObject; //Should not try to call the constructor or do any initializing
Program()
{
...
//Now call the constructor
myObject.Construct(....);
}
}
Big advantage of this solution, is that it does not require any additional allocations, and object memory allocated as normal, but you have control when call to constructor.
Another sample link
If you have access to boost, there is a handy object that is provided called boost::optional<> - this avoids the need for dynamic allocation, e.g.
class foo
{
foo() // default std::string ctor is not called..
{
bar = boost::in_place<std::string>("foo"); // using in place construction (avoid temporary)
}
private:
boost::optional<std::string> bar;
};
You may also be able to rewrite your code to use the constructor initializer list, if you can move off the other initialization into constructors:
class MyClass
{
MyObject myObject; // MyObject doesn't have a default constructor
public:
MyClass()
: /* Make sure that any other initialization needed goes before myObject in other initializers*/
, myObject(/*non-default parameters go here*/)
{
...
}
};
You need to be aware that following such a pattern will lead you to a path where you do a lot of work in constructors, which in turn leads to needing to grasp exception handling and safety (as the canonical way to return an error from a constructor is to throw an exception).
You can use a pointer (or a smart pointer) to do that. If you do not use a smart pointer, do make sure that your code free memory when the object is deleted. If you use a smart pointer, do not worry about it.
class Program
{
public:
Object * myObject;
Program():
myObject(new Object())
{
}
~Program()
{
delete myObject;
}
// WARNING: Create copy constructor and = operator to obey rule of three.
}
A trick that involves anonymous union and placement new
this is similar to jenkas' answer but more direct
class Program
{
public:
union{
Object myObject;
}; //being a union member in this case prevents the compiler from attempting to call the (undefined) default constructor
Program()
{
...
//Now call the constructor
new (&myObject) Object(...);
}
~Program()
{
myobject.~Object(); //also make sure you explicitly call the object's destructor
}
}
however the catch is that now you must explicitly define all the special member functions as the compiler will delete them by default.
I have to register an object in a container upon its creation.
Without smart pointers I'd use something like this:
a_class::a_class()
{
register_somewhere(this);
}
With smart pointers I should use shared_from_this but I can't use that in the constructor.
Is there a clean way to solve this problem? What would you do in a similar situation?
I'm thinking about introducing an init method to call just after creation and put everything in a factory function like this:
boost::shared_ptr<a_class> create_a()
{
boost::shared_ptr<a_class> ptr(new a_class);
ptr->init();
return ptr;
}
Is it fine or there is a standard procedure to follow in such cases?
EDIT: Actually my case is more complex. I have 2 object which shall maintain pointers each other. So the truth is I'm not "registering" but creating another object (let's say b_class) which requires this as a parameter. b_class receives this as a weak pointer and stores it.
I'm adding this because since you are giving me design advices (which are very appreciated) at least you can know what I'm doing:
a_class::a_class()
{
b = new b_class(this);
}
In my program a_class is an entity and b_class is one of the concrete classes representing the state (in the constructor it's just the starting state). a_class needs a pointer to the current state and b_class needs to manipulate the entity.
a_class is responsible for creating and destroying b_class instances and thus maintains a shared_ptr to them but b_class need to manipulate a_class and thus maintains a weak pointer. a_class instance "survives" b_class instances.
Do you suggest to avoid using smart pointers in this case?
a_class is responsible for creating and destroying b_class instances
...
a_class instance "survives" b_class instances.
Given these two facts, there should be no danger that a b_class instance can attempt to access an a_class instance after the a_class instance has been destroyed as the a_class instance is responsible for destroying the b_class instances.
b_class can just hold a pointer to it's associated a_class instance. A raw pointer doesn't express any ownership which is appropriate for this case.
In this example it doesn't matter how the a_class is created, dynamically, part of a aggregated object, etc. Whatever creates a_class manages its lifetime just as a_class manages the lifetime of the b_class which it instantiates.
E.g.
class a_class;
class b_class
{
public:
b_class( a_class* a_ ) : a( a_ ) {}
private:
a_class* a;
};
class a_class
{
public:
a_class() : b( new b_class(this) ) {}
private:
boost::shared_ptr<b_class> b;
};
Note, in this toy example there is no need for a shared_ptr, an object member would work just as well (assuming that you don't copy your entity class).
class a_class
{
public:
a_class() : b( this ) {}
private:
b_class b;
};
If you absolutely need a shared_ptr during construction, it's best to have an 'init' function. In fact, this is the only decent approach I can think of. You should probably have a special function that creates objects of this type, to ensure init() is called, if you choose this path.
However, depending on what you're registering for, it may be a better idea to give whatever object you're registering with a plain pointer to the object in the constructor, rather than a shared_ptr. Then in the destructor, you can just unregister the object from the manager.
Why don't you use http://www.boost.org/doc/libs/1_43_0/libs/smart_ptr/enable_shared_from_this.html
struct a_class : enable_shared_from_this<a_class> {
a_class() {
shared_ptr<a_class> ptr(this);
register_somewhere(ptr);
}
};
Update: here is a complete working example:
#include <stdio.h>
#include <boost/smart_ptr/enable_shared_from_this.hpp>
struct a_class;
boost::shared_ptr<a_class> pa;
void register_somewhere(boost::shared_ptr<a_class> p)
{
pa = p;
};
struct a_class : boost::enable_shared_from_this<a_class> {
private:
a_class() {
printf("%s\n", __PRETTY_FUNCTION__);
boost::shared_ptr<a_class> ptr(this);
register_somewhere(ptr);
}
public:
~a_class() {
printf("%s\n", __PRETTY_FUNCTION__);
}
static boost::shared_ptr<a_class> create()
{
return (new a_class)->shared_from_this();
}
};
int main()
{
boost::shared_ptr<a_class> p(a_class::create());
}
Note the factory function a_class::create(). Its job is to make sure that only one reference counter gets created. Because
boost::shared_ptr<a_class> p(new a_class);
Results in creation of two reference counters and double deletion of the object.
There is no need for shared_ptr in your code (as you show it and explain it). A shared_ptr is only appropriate for shared ownership.
Your b_class doesn't own it's a_class, in fact is even outlived by it, so it should merely keep an observing pointer.
If b_class is polymorphic and the manipulations of a_class involve altering its b_class pointer, you should use a unique_ptr<b_class>:
class a_class;
class b_class
{
friend class a_class;
a_class* mya;
b_class(a_class*p)
: mya(p) {}
public:
virtual~b_class() {} // required for unique_ptr<b_class> to work
virtual void fiddle(); // do something to mya
};
class a_class
{
std::unique_ptr<b_class> myb;
public:
a_class()
: myb(new b_class(this)) {}
template<typename B>
void change_myb()
{
myb.reset(new B(this));
}
};
I came up with a helper class for that problem:
template <class Impl>
class ImmediatelySharedFromThis : public std::enable_shared_from_this<Impl> {
typedef std::unique_ptr<void, std::function<void(void*)>> MallocGuard;
typedef std::shared_ptr<Impl> SharedPtr;
// disallow `new MyClass(...)`
static void *operator new(size_t) = delete;
static void *operator new[](size_t) = delete;
static void operator delete[](void*) = delete;
protected:
typedef std::pair<MallocGuard&, SharedPtr&> SharingCookie;
ImmediatelySharedFromThis(SharingCookie cookie) {
MallocGuard &ptr = cookie.first;
SharedPtr &shared = cookie.second;
// This single line contains the actual logic:
shared.reset(reinterpret_cast<Impl*>(ptr.release()));
}
public:
// Create new instance and return a shared pointer to it.
template <class ...Args>
static SharedPtr create(Args &&...args) {
// Make sure that the memory is free'd if ImmediatelySharedFromThis
// is not the first base class, and the initialization
// of another base class throws an exception.
MallocGuard ptr(aligned_alloc(alignof(Impl), sizeof(Impl)), free);
if (!ptr) {
throw std::runtime_error("OOM");
}
SharedPtr result;
::new (ptr.get()) Impl(SharingCookie(ptr, result),
std::forward<Args>(args)...);
return result;
}
static void operator delete(void *ptr) {
free(ptr);
}
};
class MyClass : public ImmediatelySharedFromThis<MyClass> {
friend class ImmediatelySharedFromThis<MyClass>;
MyClass(SharingCookie cookie, int some, int arguments) :
ImmediatelySharedFromThis(cookie)
// You can pass shared_from_this() to other base classes
{
// and you can use shared_from_this() in here, too.
}
public:
....
};
...
std::shared_ptr<MyClass> obj = MyClass::create(47, 11);
A bit ugly, but it works.
For this purpose, I wrote my own drop-in replacement for shared_ptr, weak_ptr and enable_shared_from_this. You can check it out at Sourceforge.
It allows call of shared_from_this() in constructor and destructor without helper functions without space overhead compared to the standard enable_shared_from_this.
Note: creating shared_ptr's in dtors is only allowed as long as they are created only temporarily. That is, they are being destroyed before the dtor returns.
Here's my solution:
class MyClass: enable_shared_from_this<MyClass>
{
public:
//If you use this, you will die.
MyClass(bool areYouBeingAnIdiot = true)
{
if (areYouBeingAnIdiot)
{
throw exception("Don't call this constructor! Use the Create function!");
}
//Can't/Don't use this or shared_from_this() here.
}
static shared_ptr<MyClass> Create()
{
shared_ptr<MyClass> myClass = make_shared<MyClass>(false);
//Use myClass or myClass.get() here, now that it is created.
return myClass;
}
}
//Somewhere.
shared_ptr<MyClass> myClass = MyClass::Create();
(The constructor has to be public to be callable from a static member function, even an internal one...)