I have a class, that doesn't have any members at all. And so, it is not intended to be instantiated. So, I deleted default c-r. That forbids any construction except list-initialization. Is there any way to forbid it too?
class Empty{
//No non-static data members
Empty()=delete;
};
Empty A{};// is allowed
Empty A ={};//is allowed too
//Empty A; ok, forbidden
//Empty A=Empty(); ok, forbidden
Empty A{}; works because Empty is an aggregate. Merely deleting the default constructor is insufficient to prevent it from being an aggregate (in C++17; in C++20, this will work).
The simplest way to do this is to give it a private member, of type char so that the type's size won't change. Alternatively, you can give it a private default constructor that isn't = defaulted.
However, just because a type is not meant to be used to make an object does not mean you should take special care to prevent it from doing so. std::enable_if<blah> is a type too, and objects of that type are not meant to be constructed. But you can still do it.
You shouldn't take these steps unless there is a genuine problem that would be caused by the user creating an object of that type.
Related
I know the general philosophy behind std::unique_ptr<T> and std::shared_ptr<T>. A unique pointer should be used in cases where no other pointer variable will ask for access to the object / primitive data pointed to by the unique pointer. A shared pointer, however, exists for shared/concurrent access to a single resource such as a file.
This all remains true for class data members of pointer types as well of course. However, in particular regards at the implementation level, does this general rule cover all cases?
Assume that you have a class with 3 member variables, all of pointer type. If none of your member functions return a pointer to one of these variables (such as a getter function) then you should declare the member variable to be of type std::unique_ptr<T>. If however, you return one these member variables then you could potentially have a situation where another pointer tries to bind to the same resource. In which case, you should declare that particular member to be of type std::shared_ptr<T>.
This seems to be a logical rule to follow. I guess, what I'm trying to figure out is how to deal with smart pointers when declared as member variables because the decision is more difficult.
A unique pointer should be used in cases where no other pointer variable will ask for access to the object / primitive data pointed to by the unique pointer. A shared pointer, however, exists for shared/concurrent access to a single resource such as a file.
I have a different understanding. The difference between unique and shared ptr is not the access. It is the lifecycle.
unique_ptr doesn't support copy semantics so it always has a single owner.
So I think for a class member variable, it depends on whether you want the class instance to be the only owner of the lifecycle.
Another benefit of unique_ptr is that, in most cases, it has the same size as a raw ptr. So it is smaller and faster than shared_ptr.
I have a class exposing through it's interface add function:
void AddObject(Object *o);
Inside the class I maintain the objects in set<shared_ptr<Object>>.
Since I will create shared_ptr from the received pointer I thought to limit the function argument to only rvalue pointers so to make sure that the user will not delete the pointer I use. And so I'll change the function declaration to:
void AddObject(Object* &&o);
so a typical use will be:
AddObject(new Object())
preventing the user to accidentally delete pointer I hold.
I don't want to to use shared_ptr in the interface because the user is not familiar with shared_ptr.
Do you think my suggestion is a good idea?
I think this is a bad idea. I'm sure there is a reason why shared_ptr c-tor that gets a raw pointer is marked explicit instead of using r-value. In my eyes, It's better to teach the users once about smart pointers or at least teach them about using make_shared/make_unique (which are safer and, in the case of make_shared, more efficient, BTW).
BTW, why shared_ptr and not unique_ptr?
Also, why set? Even if you want to make sure you hold each pointer only once and searching a vector each time doesn't look natural enough in your code, I don't see a reason to hold the pointers sorted instead of using unordered_set.
First of all, this approach will not prevent the user from deleting the pointer. Consider this example
auto obj = new Object();
AddObject(std::move(obj));
delete obj;
Secondly, the amount of steps between calling new and the creation of shared_ptr should be as few as possible. If anything happens inside AddObject before it can create a shared_ptr, the object will never get deleted.
The same applies if there are more arguments to AddObject(). If constructing those fails, you will leak memory.
void AddObject(Object* &&o, SomeOtherObject* x);
AddObject(new Object(), xx()); // if xx() throws, memory leak will occur
Ideally you would "wrap" object creating into shared_ptr construction:
void AddObject(std::shared_ptr<Object> o);
AddObject(std::make_shared<Object>());
Either of the following methods may solve your problem.
You may append more comments for AddObject to tell users that delete the pointer they added is not allowed. This is almost enough.
Or, you could also make Object inherits from a base class which has a private destructor and a method named destroyByOwner.
I have objects that define their own "right of existence". Hence they have the possibility to commit suicide. What happens to a smart pointer that holds it? Will it be dangling or does the pointer recognises that the object destroyed itself and thus point to NULL automatically?
From outside the object I would use ptr.reset(). But what can I do from inside the object?
Terrible, terrible things will happen. The smart pointer will have no idea what just happened and blindly attempt to destroy the object right on cue. This basically means that you have messed up. Objects owning themselves is highly questionable usually, but if you do own yourself, then you must never be owned externally. This directly includes smart pointers.
Proper ownership semantics means that you must have one, and only one, unambiguous owner. This is even true in the case of e.g. shared_ptr, where the object is effectively owned by the reference count.
A self-owning object must be clear about the fact that it owns itself and it is not to be owned externally.
There is a way to do want you want...
The object must keep itself alive using a shared_ptr to itself. If that is the only shared_ptr, then the object can suicide by decrementing the shared_ptr (Probably not a good idea to call reset() having the shared_ptr destroy itself. A better approach is to move the member shared_ptr into a temporary, so the shared_ptr member getting destroyed is not the same shared_ptr as the one causing destruction)
Then, from outside the objects you can use std::weak_ptr, and these will know when the object is destroyed. (Because there is really a metadata object that survives and contains the state, and the weak_ptr checks this before accessing the object.)
It probably makes sense to inherit enable_shared_from_this for such an object, and then make your constructors private and friend make_shared. That way it's impossible for an object instance to exist that is not managed using the internal shared_ptr.
I would suggest using an intrusive pointer. See: Boost intrusive_ptr.
Your object would need an internal reference count. In your implementation of the member function intrusive_ptr_release you could skip clean-up if your object has already 'comitted suicide'.
What is the best way to document the type of parameters that a function expects to receive?
Sometimes a function uses only one or two fields of an object. Sometimes this fields have common names (get(), set(), reset(), etc.). In this situation we must leave a comments:
...
#staticmethod
def get( postId, obj ):
"""obj is instance of class Type1, not Type2"""
inner = obj.get()
Is there a more explicit way to make it obvious? Maybe an object name should contain expecting typename?
Given python's 'duck-typing' (late bound) behaviour, it would be a mistake to require a particular type.
If you know which types your function must not take, you can raise an exception after detecting those; otherwise, simply raise an exception if the object passed does not support the appropriate protocol.
As to documentation, just put the required protocol in the docstring.
One strength of python is "duck typing", that is not to rely on the actual type of a variable, but on its behaviour. So I'd suggest, that you document the field, that the object should contain.
"""obj should have a field 'foo' like in class 'bar' or 'baz' """
First of all, name your methods properly, and use properties if they make sense.
You should try to get the hang of duck-typing. It's pretty useful. And if not, try and see if abstract base classes helps you do what you want.
Is it legal/proper c++0x to leave an object moved for the purpose of move-construction in a state that can only be destroyed? For instance:
class move_constructible {...};
int main()
{
move_constructible x;
move_constructible y(std::move(x));
// From now on, x can only be destroyed. Any other method will result
// in a fatal error.
}
For the record, I'm trying to wrap in a c++ class a c struct with a pointer member which is always supposed to be pointing to some allocated memory area. All the c library API relies on this assumption. But this requirement prevents to write a truly cheap move constructor, since in order for x to remain a valid object after the move it will need its own allocated memory area. I've written the destructor in such a way that it will first check for NULL pointer before calling the corresponding cleanup function from the c API, so that at least the struct can be safely destroyed after the move.
Yes, the language allows this. In fact it was one of the purposes of move semantics. It is however your responsibility to ensure that no other methods get called and/or provide proper diagnostics. Note, usually you can also use at least the assignment operator to "revive" your variable, such as in the classical example of swapping two values.
See also this question