I am trying to really move from c++98 to c++11 and newer. I have wrapped my head over most of the new stuff but I am still not sure about the correct usage of unique_ptr.
Consider the example below, where class A has a unique_ptr member (I would have used raw pointer before!). This member variable should be assigned, when user needs, by calling a function somewhere else (not part of the class). Is this the correct usage? If not, what is the best alternative?
class A {
private:
unique_ptr<MyType> mt;
public:
void initStuff() {
mt.reset(std::move(StaticFuncSomewhereElese::generateMyType()));
}
};
MyType* StaticFuncSomewhereElese::generateMyType() {
MyType* temp = new MyType(...);
//do stuff to temp (read file or something...)
return temp;
}
Your code works fine (although the redundant* move can be omitted) but it would be better to construct the unique_ptr as early as possible:
class A {
private:
std::unique_ptr<MyType> mt;
public:
void initStuff() {
mt = StaticFuncSomewhereElese::generateMyType();
}
};
std::unique_ptr<MyType> StaticFuncSomewhereElese::generateMyType() {
auto temp = std::make_unique<MyType>(…);
// `make_unique` is C++14 (although trivially implementable in C++11).
// Here's an alternative without `make_unique`:
// std::unique_ptr<MyType> temp(new MyType(…));
//do stuff to temp (read file or something...)
return temp;
}
This way it is clear that the return value of generateMyType must be deleted by the caller, and there's less possibility for memory leaks (e.g. if generateMyType returns early).
* The move is redundant because:
Raw pointers can't be moved.
The result of the generateMyType() expression is already an rvalue anyways.
Is this the correct usage?
Besides std::move being redundant, yes this is correct. It is redundant because a) Bare pointers are copied, whether they are lvalues or rvalues and b) The function doesn't return a reference, so the return value is already an rvalue so there is no need to convert.
But there is room for improvement. In particular, I recommend to return a unique pointer from the factory function:
std::unique_ptr<MyType> StaticFuncSomewhereElese::generateMyType()
This prevents temp from leaking if the initialization throws an exception, and makes it much harder for the user of the factory to accidentally leak the returned pointer.
Why not make it a generic template factory?
In header.
template <typename T>
std::unique_ptr<T> generateMyType();
classss A {
private:
std::unique_ptr<MyType> mt;
std::unique_ptr<MyOtherType> mot;
public:
void initStuff() {
mt = generateMyType<MyType>();
mot = generateMyType<MyOtherType>();
}
};
And in the source file
template <typename T>
std::unique_ptr<T> generateMyType()
{
auto temp = std::make_unique<T>();
return temp;
}
Related
I'm working with a code base right now, and there's this section that has the following:
if(const auto *temp_ptr = obj->get_ptr()) {
perm_ptr = std::move(temp_ptr);
}
What is the point of the std::move in this case when it's just a simple pointer? It doesn't seem there's any advantage over simply doing perm_ptr = temp_ptr?
As said in the comments, if the type of perm_ptr is a raw pointer type, then the move is pointless.
However, it is possible to define a type for perm_ptr that would make this syntax meaningful. Whether it would be useful is at best highly debatable, and results in unintuitive and unconventional code.
It involves defining an assignment operator that only accepts a RValue to a pointer. Like so: operator=(T*&& p);.
This could, for instance, be used to ensure that no one accidentally assigns a raw pointer to something that will eventually calling delete on it without doing so intentionally.
It could also be used to reset the pointer to nullptr (or some other value) as part of the assignment.
#include <utility>
template<typename T>
struct my_unique_ptr {
~my_unique_ptr() {
if(ptr_) delete ptr_;
}
my_unique_ptr& operator=(T*&& p) {
ptr_ = p;
p = nullptr;
return *this;
}
private:
T* ptr_ = nullptr;
};
int main() {
my_unique_ptr<int> perm_ptr ;
int* ptr = new int;
// all good.
owning_ptr = std::move(ptr);
// compile error!
owning_ptr = ptr;
}
To be 100% clear: This is a only an example that could result in the program presented by the OP being intentional and meaningful. I am not advocating for such a technique. Even if it was a good idea, it would still be fraught with caveats and pitfalls that are not being covered by this answer.
I want to write safe C++ programs, therefore:
I wanted to avoid memory leaks, so I started using std::shared_ptr.
However, I still had some null pointer deferences some times. I've come up with the idea of using using MyClassSafe = std::optional<std::shared_ptr<MyClass>>.
Then I avoid both memory leaks and null pointer deference. Well, kind of. For example:
MyClassSafe myClassSafe = std::make_shared<MyClass>();
//Then everytime I want to use myClassSafe:
if (myClassSafe) {
//use it here
} else {
//do something in case no value
}
//However, this situation can be possible:
MyClassSafe notVerySafe = std::make_shared<MyClass>(nullptr); // or = std::shared_ptr(nullptr);
if (myClassSafe) {
//use it here, for example:
//this deferences a nullptr
myClassSafe.value()->someFunction();
} else {
//do something in case no value
}
so this is not much safer. It's better but I still can make mistakes.
I can imagine a safe_shared_ptr<T> class that instead of calling the object's functions on operator->, it could return std::optional<T&> (much like Rust) for which we can then safely call or deal with the std::nullopt case. Isn't there something already in C++? Or can it be implemented easily?
You haven't shown need for either pointers or optionals here.
MyClass myClassSafe;
myClassSafe.someFunction();
No possibility of null pointers or empty optionals in sight.
optional<T> allows you to handle the "no T available" case, which shared_ptr<T> already handles. Therefore optional<shared_ptr<T>> is redundant, just like optional<optional<T>> is.
There is a case to be made for shared_ptr<optional<T>> - if one owner creates the T object, the other owner can see the new object, so that isn't really redundant.
Your use of std::optional here is the cause of the problem. std::shared_ptr defines operator bool as a null pointer check, but because you have wrapped it in std::optional this never gets called
If instead you try:
MyClass myClass = std::make_shared<MyClass>(nullptr); // or = std::shared_ptr(nullptr);
if (myClass) {
// std::shared_ptr implements operator bool as a null pointer check
myClass->someFunction();
} else {
//do something in case no value
}
Isn't there something already in C++?
There is nothing in std to handle non null smart pointer.
As Caleth shows in his answer, you can use object directly and avoid (smart) pointer and std::optional.
Or can it be implemented easily?
Non null smart pointer (a "smart reference" :) ) should be non default constructible, and "non-movable" (I mean move should not invalidate the reference).
You could implement it with existing smart pointer, something like:
template <typename T>
class unique_ref
{
public:
// Avoid variadic constructor which might take precedence over regular copy/move constructor
// so I use tag std::in_place_t here.
template <typename ... Ts>
unique_ref(std::in_place_t, Ts&&... args) : std::make_unique<T>(std::forward<Ts>(args)...) {}
unique_ref(const unique_ref&) = delete;
unique_ref(unique_ref&&) = delete;
unique_ref& operator=(const unique_ref&) = delete;
unique_ref& operator=(unique_ref&&) = delete;
const T& operator*() const { return *ptr; }
T& operator*() { return *ptr; }
const T* operator ->() const { return ptr.get(); }
T* operator*() { return ptr.get(); }
private:
std::unique_ptr<T> ptr;
};
template <typename T, typename ... Ts>
unique_ref<T> make_unique_ref(Ts&&... args)
{
return {std::in_place, std::forward<Ts>(args)...};
}
unique version is not much useful, as non-copyable, non-movable. using directly T seems simpler.
shared version is copyable (its move should do identical to the copy)
A weak version might return an std::optional<shared_ref<T>>.
Real example is obviously much longer, but this sums up my problem:
class Object
{
int mInt1,mInt2;
Object::Object();
Object::Object(int param1);
Object::Object(int param1, int param2);
};
Object::Object(){}
Object::Object(int param1):mInt1(param1){}
Object::Object(int param1, int param2):mInt1(param1),mInt1(param2){}
Then in main:
if (type1){
Object instance(param1);
}
else{
Object instance(param1,param2);
}
// do stuff with instance
Whoops! That won't work, instance is out of scope for the program that follows.
Object instance;
if (type1){
instance = Object(param1);
}
else{
instance = Object(param1,param2);
}
// do stuff with instance
But now I run in to trouble because I didn't have a copy constructor defined. I'd really rather not write a copy-constructor because my actual class has dozens of members, many of which are non-basic types and might require even more work to copy.
Specifically, I am getting
main.cpp: error: use of deleted function ‘Object& Object::operator=(Object&&)’
instance = Object(param1);
^
note: ‘Object& Object::operator=(Object&&)’ is implicitly deleted because the default definition would be ill-formed:
The universal way to deal with non-copyable objects is to throw it into a unique_ptr (or auto_ptr, depending on your compiler).
std::unique_ptr<Object> instance;
if (type1) {
instance.reset(new Object(i));
}
else {
instance.reset(new Object(i, j));
}
Using raw pointers here really isn't safe because once you start having to deal with exceptions or any interesting code paths it becomes a chore to worry about leaks. Trust me, in 100% of cases, you will have less work and lines of code to deal with if you just drop it in a unique_ptr.
An optimal solution would be to redesign Object's constructors, because circumventing non-copyability may leave the object in an illegal state. In general, you want to preserve non-copyability if the compiler thinks it's necessary. We don't have the details here to flesh out such a solution however.
If you do not want dynamically allocation then you can use an Initialize function:
class Object
{
int mInt1,mInt2;
Object::Object();
Object::Initialize();
Object::Initialize(int param1);
Object::Initialize(int param1, int param2);
};
Object::Object(){Initialize();} //call the empty Initialize for nice coding...:)
Object::Initialize(){ }
Object::Initialize(int param1){ mInt1(param1); }
Object::Initialize(int param1, int param2){ mInt1(param1);mInt1(param2);}
Then you can use initialize to select the type.
Object instance;
if (type1){
instance.Initialize(param1);
}
else{
instance.Initialize(param1,param2);
}
Here is a low-level(ish) solution which does what you want. I will leave it up to you to decide whether it's a good idea to use it:
#include <type_traits>
template <class T>
class MultiInitialiser
{
T *object;
std::aligned_storage<T> storage;
public:
MultiInitialiser() : object(nullptr)
{}
template <class... Arg>
void initialise(Arg &&... arg)
{
if (object)
throw "Double init error";
object = new (&storage) T(std::forward<Arg>(arg)...);
}
operator T& ()
{ return *object; }
operator const T& () const
{ return *object; }
~MultiInitialiser()
{
if (object)
object->~T();
}
};
Copy/move operations for the above are left as an excercise for the reader ;-)
The class would then be used like this:
MultiInitialiser<Object> instance;
if (type1){
instance.initialise(param1);
}
else{
instance.initialise(param1,param2);
}
Apart from the cast to T, you could also give the class operator* and operator-> returning the contained object, similar to what boost::optional does.
There are a couple of options that let you do this while retaining automatic storage, and which one you should use depends on the semantics of the type Object.
The POD
If you have a type like the one given in the question, you might choose to reduce it to a POD type; basically, remove all of the user-provided constructors and give everything the same access specifier:
struct Object {
int mInt1, mInt2;
};
Then, your initialization pattern might look like this (using placement new):
Object o; // Default-initialized, a no-op
if (condition)
new (&o) Object {i};
else
new (&o) Object {i, j};
General Types
Generally speaking, your typical value-semantic type will work perfectly fine if you default-initialize and then assign, thanks to move semantics:
std::vector <foo> v;
if (condition)
v = std::vector <foo> (42);
else
v = std::vector <foo> {bar, baz, quux};
Often, though, you'll still be doing work in the default constructor, because certain types' default-constructed objects (e.g., std::vector) have well-defined state. If you want to avoid this work for an arbitrary predefined type, you might want to use std::optional (as of this writing not actually yet standard):
std::optional <big_but_flat> b;
if (condition)
b.emplace (i);
else
b.emplace (i, j);
Without std::optional
You might object that std::optional has too much overhead associated with it, and I'll leave it to you and your measurements to decide whether that's the case. At any rate, we can get our behaviour without worrying about that overhead— but may the nasal demons have mercy if you don't actually perform your initialization. We'll use a union to get what we want:
// At function scope
union store_v {
std::vector <int> v;
store_v () {}
~store_v () { v.~vector <int> (); }
} sv;
if (condition)
new (&sv.v) std::vector <int> (42);
else
new (&sv.v) std::vector <int> {49, 343, 2401};
This may be improved. For example, we can make the storage a template:
template <typename T>
union store {
T t;
store () {}
~store () { t.~T (); }
};
// At function scope
store <std::vector <int>> sv;
if (condition)
new (&sv.t) std::vector <int> (42);
else
new (&sv.t) std::vector <int> {49, 343, 2401};
We can give ourselves a reference:
template <typename T>
union store {
T t;
store () {}
~store () { t.~T (); }
};
// At function scope
store <std::vector <int>> sv;
auto&& v = sv.t; // Deduce const, for what that's worth
if (condition)
new (&v) std::vector <int> (42);
else
new (&v) std::vector <int> {49, 343, 2401};
And with a little attention to detail to avoid name collisions and handle C++'s… interesting declaration syntax, we could even define a couple of macros to clean the code up (implementation left as an exercise to the reader):
template <typename T>
union store {
T t;
store () {}
~store () { t.~T (); }
};
// At function scope
DECL_UNINIT (std::vector <int>, v);
if (condition)
INIT (v, (42));
else
INIT (v, {49, 343, 2401});
You can use a pointer to your object and instantiate it by new operator:
Object * instance;
if (type1){
instance = new Object(param1);
}
else{
instance = new Object(param1,param2);
}
You're using something that is called copy elision.
This states that the compiler MAY optimize the code and avoid a copy constructor in such a case.
But it doesn't have to, and may use a copy constructor anyway.
The right way (without being subjected to the whims of the compiler) would be to use a pointer:
Object* instance;
if (type1){
instance = new Object(param1);
}
else{
instance = new Object(param1,param2);
}
In your version of one-parameter constructor, the mInt2 member is just ignored (isn't ever initialized), so I assume that you don't do any computation with that member if type1 is false (though I don't know how you're doing it without storing type1).
So, why don't just change the dessign? Make te constructor take int param1, int param2 and type1 as parameters and choose internally how to build himself:
class Object
{
int mInt1,mInt2;
Object::Object() :
mInt1(0), // don't forget to initialize your values!
mInt2(0)
{}
// Object::Object(int param1); no more 1-parameter ctor.
Object::Object(int param1, int param2, type type1) :
mInt1(param1),
mInt2(type1 ? param2 : 0) // assuming that 0 isn't a valid value for mInt2
{}
};
Then in main:
Object instance(param1, param2, type1);
// do stuff with instance
I guess that it looks a little neater.
You could write a move assignment. Depending what your data members look like, you may get away with memcopying some or all of them, cf. Move constructor with memcpy.
That said, I assume that either you need a full set of constructors/destructors, including copy and assignment; that will always be necessary if you want to have it in containers, assign it etc. Or else the class doesn't need any of that and you just initialize the needed parts of it depending on the situation, and when you are done, you de-initialize manually.
I think I found a way to do it without requiring allocating the object on the heap, using a lambda.
Basically, the idea is to separate the construction from the usage. (the following assume that you fixed the difinition of Object so that it compiles)
auto work = []( Object& object ){
// here do the work on the object
};
// now create the object and apply the work in the process:
if (type1){
Object instance(param1);
work( instance );
}
else{
Object instance(param1,param2);
work( instance );
}
Here no copy was involved but the same code is still applied whatever the wy the object was constructed, and without having to declare an external function (as a lambda is a local function).
From the memory point of view, there will always be only one instance object so the stack memory allocated will always be the same size whatever the path.
Obviously, this don't work if the instance have to get out of the scope of the whole function. If it's the case, then you really need to allocate it on the heap using a smart pointer preferably.
I have a question similar to How to manage object life time using Boost library smart pointers? but, in my case, the "object" isn't a C++ object at all, but an opaque type returned/passed out from a C API. The type does not have pointer semantics, i.e., there is no dereferencing; it is, however, passed as an argument to other functions in the C API. The type also has a definitive close API which must be called in order to clean up internal resources.
So, I have a C API that's something along the lines of
opaque_legacy_type_t x;
XXopen(..., &x); // allocates/opens resource and fills out 'x' to be used later
XXdoSomethingWithResource(x, ...); // do something with resources related to 'x'
...more actions...
XXclose(x); // closes and cleans up resources related to 'x'
For various reasons, in my C++ code I would like to manage "instances" of opaque_legacy_type_t much like I would manage heap-allocated object instances, i.e. with similar sharing semantics as boost::shared_ptr<>. It seems that shared_ptr offers enough that I can manage calling XXclose by doing this:
opaque_legacy_type_t x;
XXopen(..., &x);
boost::shared_ptr<opaque_legacy_type_t> managed(x, XXclose);
But, since opaque_legacy_type_t doesn't have pointer semantics, the usage of managed is a bit clumsy.
What I'd like to do is have something like a managed_type that is similar to shared_ptr, and am looking for ideas that don't require me to write it all.
EDIT: I corrected my original screw-up in the example. The legacy API takes the opaque type by value rather than by pointer.
Since all of the legacy API take a pointer to the opaque type, you could use shared pointers directly. The key is for you to not declare the original structure on the stack, but rather allocate it via new:
int main () {
std::shared_ptr<opaque_legacy_type_t> x(new opaque_legacy_type_t,
[](opaqeue_legacy_type_t* p) { XXClose(p); delete p; });
XXopen(..., x.get());
XXdoSomethingWithResource(x.get(), ...);
}
EDIT: If some API take the opaque type by value instead of pointer, then pass the dereferenced pointer.
int main () {
std::shared_ptr<opaque_legacy_type_t> x(new opaque_legacy_type_t,
[](opaqeue_legacy_type_t* p) { XXClose(*p); delete p; });
XXopen(..., x.get());
XXdoSomethingWithResource(*x, ...);
}
You could use boost smart pointers together with the pimpl idom:
class shared_opaque_legacy_type_t {
struct impl {
opaque_legacy_type_t t;
impl(...) { XXOpen(..., t); }
~impl(...) { XXClose(t); }
}
boost::shared_ptr<impl> _impl;
public:
shared_opaque_lagacy_type_t(...) : _impl(new impl(...)) {}
opaque_legacy_type_t* get() {
return _impl->t;
}
};
shared_opaque_legacy_type_t x(...);
XXdoSomethingWithResource(x.get(), ...);
The drawback is that you could still call XXclose(x.get()) and invalidate your object.
UPDATE: Fixed it. :-)
You could write a wrapper to use with boost that will call the open() in the ctor and the close() in the dtor.
I voted for Rob's answer that just uses a shared_ptr with no wrapper, but if you really want to avoid dynamic allocation here's a simple little example of how to do that.
It's a template that directly holds the handle and does no allocation. You pass the constructor a functor that creates an object of the opaque type, and a deleter to call when the type needs to be destroyed. It's movable and non-copyable so now shared reference count is needed. It implements implicit conversion operators so you can use it where you'd use a value of the held type.
template<typename T,typename D>
class opaque_type_handle {
T handle;
D deleter;
bool needs_delete;
public:
template<typename F>
opaque_type_handle(F f,D d) : handle(f()), deleter(d), needs_delete(true) {}
opaque_type_handle(opaque_type_handle const &) = delete;
opaque_type_handle &operator=(opaque_type_handle const &) = delete;
opaque_type_handle(opaque_type_handle &&rhs) : handle(rhs.handle),deleter(rhs.deleter),needs_delete(true) {
rhs.needs_delete = false;
}
opaque_type_handle &operator=(opaque_type_handle &&rhs) {
handle = rhs.handle;
deleter = rhs.deleter;
needs_delete = true;
rhs.needs_delete = false;
returh *this;
}
~opaque_type_handle() {
if(needs_delete) {
deleter(handle);
}
}
operator T&() { return handle; }
operator T() const { return handle; }
};
Use it like so:
// wrap up the code for creating an opaque_legacy_type_t handle
typedef opaque_type_handle<opaque_legacy_type_t,decltype(&XXclose)> legacy_handle;
legacy_handle make_legacy_handle(...) {
return legacy_handle(
[](){
opaque_legacy_type_t tmp;
XXopen(..., &tmp);
return tmp;
},
&XXclose
);
}
legacy_handle x = make_legacy_handle(...);
XXdoSomethingWithResource(x,...);
I wrote a class to contain my objects in it.
The code is:
class objectPool
{
private:
struct itemType_{uint count; void* object;};
std::multimap< std::string, itemType_ > pool_;
public:
template<class T>
bool addItem(std::string key, T*& object)
{
std::multimap< std::string, itemType_ >::iterator
i = pool_.find(key);
if(i != pool_.end())
{
object = (T*)(*i).second.object;
(*i).second.count++;
return true;
}
i = pool_.insert(std::pair<std::string,itemType_>(key, (itemType_){1, NULL}));
object = (T*)(*i).second.object;
return false;
}
template<class T>
bool removeItem(std::string key)
{
std::multimap< std::string, itemType_ >::iterator
i = pool_.find(key);
if(i != pool_.end())
{
if((*i).second.count == 1)
{
//important to call the appropriate destructor
delete ((T*)(*i).second.object);
pool_.erase(i);
}
else
(*i).second.count--;
return true;
}
return false;
}
};
And the test code:
#include "objectPool.h"
class testClass
{
public:
~testClass()
{
// I should get here at least once
std::cout << "I am deleted teehee";
}
};
testClass* test;
objectPool myPool;
int main () {
if(!myPool.addItem<testClass>("baba", test))
{
test = new testClass;
}
myPool.removeItem<testClass>("baba");
}
For some reason my test object's destructor does not want to be invoked.
First questcha: Why? Where I am wrong?
The sec.: Should I use auto_ptr instead? (Although I want to avoid using templates...)
The third.: Is there a better(-looking) solution? (with or without using templates)
The fourth.: Is there a way to invoke constructor via void pointer without templates (or without knowing the original type)?
Thanks ahead! :D
And sorry for my terrific english (not my native language, although...)
You correctly store a NULL into your T* reference, but that is a reference to the local variable. When you later update that local by calling new, that has no effect on the item stored in the pool.
The easier way to fix this would be to just create the object inside the addItem function using new T.
As for your other question, a way to call the destructor without knowing the original type, there is no way to do that. But there is a trick you can use with templates. You can create a template function like the one below, and then pass around a function pointer to it.
template<typename T>
void deleter(void *ptr)
{
delete static_cast<T*>(ptr);
}
deleter as a simple type which you can typedef and pass around pointers:
typedef void (*deleter_func)(void *);
To get a pointer to it, just do something like this in your addItem function:
deleter_func myDeleter = &deleter<T>;
Then later:
myDeleter(somePtr);
You don't need to know the type of somePtr at the time of deletion, just need to keep a pointer to the deleter. You can also use this method with shared_ptr, which can use a deleter argument.
My guess is it's going wrong because you're inserting {1, NULL} into the map. Changing the value of test in the main function doesn't affect the content of the map.
For some reason my test object's destructor does not want to be invoked. First questcha: Why? Where I am wrong?
Your test code is wrong. You add some uninitialized pointer into the structure. Try this:
int main () {
test = new testClass();
if(!myPool.addItem<testClass>("baba", test))
{
// Duplicate, I presume...
}
myPool.removeItem<testClass>("baba");
}
The sec.: Should I use auto_ptr instead?
std::auto_ptr is designed for dynamically allocated local variables, it is not designed for container implementation. Your current design limits that, anyways. However, I would write the test code as
int main () {
std::auto_ptr<testClass> test(new testClass());
if(myPool.addItem<testClass>("baba", test.get()))
{
test.release();
}
myPool.removeItem<testClass>("baba");
}
The third.: Is there a better(-looking) solution?
Yes, there is some type-safe heterogenous container in boost. I would look at that.
The fourth.: Is there a way to invoke constructor via void pointer without templates (or without knowing the original type)?
You can use the placement new operator if you want to construct an object in pre-allocated memory. std::vector does this a lot. However, there is no way to construct an object without knowing the type. How would you specify what type's constructor to invoke? If you need this, you'll probably want to look into the factory method pattern.