I know 2 ways:
// Declared somewhere but not on stack
shared_ptr<X> xptr = make_shared<X>();
xptr = nullptr; //#1
xptr.reset(); //#2
As for me #1 looks better, but what is better from the point of C++
Neither is objectively better. In almost every case, the difference is purely aesthetic.
The only exception that I can think of is writing a generic function template that works with both smart, and bare pointers. only ptr = nullptr is valid syntax for bare pointers.
The assignment and reset member function differ in behaviour only when the pointer is not null.
Related
As we know, STL usually offered two kinds of functions to insert an element: insert/push and emplace.
Let's say I want to emplace all of elements from one container to another.
for (auto &&element : myMap)
{
anotherMap.emplace(element); // vs anotherMap.empalce(std::move(element));
}
In this case, if I want to call the emplace, instead of insert/push, must I still call std::move here or not?
If you indeed want to move all elements from myMap into anotherMap then yes you must call std::move(). The reason is that element here is still an lvalue. Its type is rvalue reference as declared, but the expression itself is still an lvalue, and thus the overload resolution will give back the lvalue reference constructor better known as the copy constructor.
This is a very common point of confusion. See for example this question.
Always keep in mind that std::move doesn't actually do anything itself, it just guarantees that the overload resolver will see an appropriately-typed rvalue instead of an lvalue associated with a given identifier.
I've been trying to nail down the rule of 5, but most of the information online is vastly over-complicated, and the example codes differ.
Even my textbook doesn't cover this topic very well.
On move semantics:
Templates, rvalues and lvalues aside, as I understand it, move semantics are simply this:
int other = 0; //Initial value
int number = 3; //Some data
int *pointer1 = &number; //Source pointer
int *pointer2 = &other; //Destination pointer
*pointer2 = *pointer1; //Both pointers now point to same data
pointer1 = nullptr; //Pointer2 now points to nothing
//The reference to 'data' has been 'moved' from pointer1 to pointer2
As apposed to copying, which would be the equivalent of something like this:
pointer1 = &number; //Reset pointer1
int newnumber = 0; //New address for the data
newnumber = *pointer1; //Address is assigned value
pointer2 = &newnumber; //Assign pointer to new address
//The data from pointer1 has been 'copied' to pointer2, at the address 'newnumber'
No explanation of rvalues, lvalues or templates is necessary, I would go as far as to say those topics are unrelated.
The fact that the first example is faster than the second, should be a given. And I would also point out that any efficient code prior to C++ 11 will do this.
To my understanding, the idea was to bundle all of this behavior in a neat little operator move() in std library.
When writing copy constructors and copy assignment operators, I simply do this:
Text::Text(const Text& copyfrom) {
data = nullptr; //The object is empty
*this = copyfrom;
}
const Text& Text::operator=(const Text& copyfrom) {
if (this != ©from) {
filename = copyfrom.filename;
entries = copyfrom.entries;
if (copyfrom.data != nullptr) { //If the object is not empty
delete[] data;
}
data = new std::string[entries];
for (int i = 0; i < entries; i++) {
data[i] = copyfrom.data[i];
//std::cout << data[i];
}
std::cout << "Data is assigned" << std::endl;
}
return *this;
}
The equivalent, one would think, would be this:
Text::Text(Text&& movefrom){
*this = movefrom;
}
Text&& Text::operator=(Text&& movefrom) {
if (&movefrom != this) {
filename = movefrom.filename;
entries = movefrom.entries;
data = movefrom.data;
if (data != nullptr) {
delete[] data;
}
movefrom.data = nullptr;
movefrom.entries = 0;
}
return std::move(*this);
}
I'm quite certain this won't work, so my question is: How do you achieve this type of constructor functionality with move semantics?
It's not entirely clear to me what is supposed to be proved by your code examples -- or what the focus is of this question is.
Is it conceptually what does the phrase 'move semantics' mean in C++?
Is it "how do I write move ctors and move assignment operators?" ?
Here is my attempt to introduce the concept. If you want to see code examples then look at any of the other SO questions that were linked in comments.
Intuitively, in C and C++ an object is supposed to represent a piece of data residing in memory. For any number of reasons, commonly you want to send that data somewhere else.
Often one can take a direct approach of simply passing a pointer / reference to the object to the place where the data is needed. Then, it can be read using the pointer. Taking the pointer and moving the pointer around is very cheap, so this is often very efficient. The chief drawback is that you have to ensure that the object will live for as long as is needed, or you get a dangling pointer / reference and a crash. Sometimes that's easy to ensure, sometimes its not.
When it isn't, one obvious alternative is to make a copy and pass it (pass-by-value) rather than passing by reference. When the place where the data is needed has its own personal copy of the data, it can ensure that the copy stays around as long as is needed. The chief drawback here is that you have to make a copy, which may be expensive if the object is big.
A third alternative is to move the object rather than copying it. When an object is moved, it is not duplicated, and instead becomes available exclusively in the new site, and no longer in the old site. You can only do this when you won't need it at the old site anymore, obviously, but in that case this saves you a copy which can be a big savings.
When the objects are simple, all of these concepts are fairly trivial to actually implement and get right. For instance, when you have a trivial object, that is, one with trivial construction / destruction, it is safe to copy it exactly as you do in the C programming language, using memcpy. memcpy produces a byte-for-byte copy of a block of bytes. If a trivial object was properly initialized, since its creation has no possible side-effects, and its later destruction doesn't either, then memcpy copy is also properly initialized and results in a valid object.
However, in modern C++ many of your objects are not trivial -- they may "own" references to heap memory, and manage this memory using RAII, which ties the lifetime of the object to the usage of some resource. For instance, if you have a std::string as a local variable in a function, the string is not totally a "contiguous" object and rather is connected to two different locations in memory. There is a small, fixed-size (sizeof(std::string), in fact) block on the stack, which contains a pointer and some other info, pointing to a dynamically sized buffer on the heap. Formally, only the small "control" part is the std::string object, but intuitively from the programmer's point the buffer is also "part" of the string and is the part that you usually think about. You can't copy a std::string object like this using memcpy -- think about what will happen if you have std::string s and you try to copy sizeof(std::string) bytes from address &s to get a second string. Instead of two distinct string objects, you'll end up with two control blocks, each pointing to the same buffer. And when the first one is destroyed, that buffer is deleted, so using the second one will cause a segfault, or when the second one is destroyed, you get a double delete.
Generally, copying nontrivial C++ objects with memcpy is illegal and causes undefined behavior. This is because it conflicts with one of the core ideas of C++ which is that object creation and destruction may have nontrivial consequences defined by the programmer using ctors and dtors. Object lifetimes may be used to create and enforce invariants which you use to reason about your program. memcpy is a "dumb" low-level way to just copy some bytes -- potentially it bypasses the mechanisms that enforce the invariants which make your program work, which is why it can cause undefined behavior if used incorrectly.
Instead, in C++ we have copy constructors which you can use to safely make copies of nontrivial objects. You should write these in a way that preserves what invariants you need for your object. The rule of three is a guideline about how to actually do that.
The C++11 "move semantics" idea is a collection of new core language features which were added to extend and refine the traditional copy construction mechanism from C++98. Specifically, it's about, how do we move potentially complex RAII objects, not just trivial objects, which we already were able to move. How do we make the language generate move constructors and such for us automatically when possible, similarly to how it does it for copy constructors. How do we make it use the move options when it can to save us time, without causing bugs in old code, or breaking core assumptions of the language. (This is why I would say that your code example with int's and int *'s has little to do with C++11 move semantics.)
The rule of five, then, is the corresponding extension of the rule of three which describes conditions when you may need to implement a move ctor / move assignment operator also for a given class and not rely on the default behavior of the language.
#define __verify_pcpu_ptr(ptr)
do {
const void __percpu *__vpp_verify = (typeof((ptr) + 0))NULL;
(void)__vpp_verify;
} while (0)
#define VERIFY_PERCPU_PTR(__p)
({
__verify_pcpu_ptr(__p);
(typeof(*(__p)) __kernel __force *)(__p);
})
What do these two functions do? What are they used for? How do they work?
Thanks.
This is part of the scheme used by per_cpu_ptr to support a pointer that gets a different value for each CPU. There are two motives here:
Ensure that accesses to the per-cpu data structure are only made via the per_cpu_ptr macro.
Ensure that the argument given to the macro is of the correct type.
Restating, this ensures that (a) you don't accidentally access a per-cpu pointer without the macro (which would only reference the first of N members), and (b) that you don't inadvertently use the macro to cast a pointer that is not of the correct declared type to one that is.
By using these macros, you get the support of the compiler in type-checking without any runtime overhead. The compiler is smart enough to eventually recognize that all of these complex machinations result in no observable state change, yet the type-checking will have been performed. So you get the benefit of the type-checking, but no actual executable code will have been emitted by the compiler.
In both C++11 and boost, smart pointers can be nullptr. I wonder why. That means that smart pointers must be checked for being nullptr every time they are passed to interface method from uncontrolled client code. Obviously, such check is performed in run time.
What if there would be smart pointers that can be created only via make_shared or make_unique and cannot be reset or reassigned to nullptr or raw pointer? This approach allows to ensure that pointer is not nullptr in compile time.
For example, in Java we always must check if object is not null (bad). But in Swift, we can explicitly make sure that argument (or variable) is not null in compile time (good).
UPD:
Well, thank you much for answers and comments. I got idea. But is there any popular libraries that supports non-nullity compile time guarantee alongside ownership, maybe smart pointer wrappers?
std smart pointers exist for one reason—to implement the concept of ownership. Their responsibility is to clearly define who owns the pointee (i.e. who and how ensures its safe destruction).
Large parts of std are really composed of low-level basic building blocks. While they can be used straight away in client code, they are not supposed to be an all-encompassing solution. They give you single-purpose tools which you cna mix & match to create something you need.
The std smart pointers are eactly "raw pointers + ownership." Raw pointers can be null and can be reseated, so std smart pointers can as well. Nothing prevents you from creating your own "std smart pointer + non-nullity" class(es) and using them in your code.
On the other hand, there are very valid use cases for a null smart pointer. If std smart pointers enforce non-nullity, and you needed null-supporting smart pointers, you'd have a much harder time implementing that. It's easier to add a validity constraint than to remove it when you can only do it by adding to the original class.
For std::unique_ptr is impossible to require no null, consider this:
std::unique_ptr<int> p = std::make_unique<int>();
std::unique_ptr<int> q = std::move(p);
What value will have p and q? If we ban null option this become impossible to implement. Even if we consider destroying move, we will have even worse situation. This is because you will be not allowed to test p, any use will be UB.
For std::share_ptr It could be possible to require it but this will heavy hinder any other use that could used nullable pointers. Standard library is too generic to allow that limitation.
Overall idea of having compile time guarantee of existing object pointed by pointer is very valuable but you try used wrong tool for this. Usually this is done by using & not pointers.
To solve your needs I suggest creating warper around std::share_ptr:
template<typename T>
class always_ptr
{
std::shared_ptr<T> _ptr;
public:
always_ptr() = delete; //no default constructor
always_ptr(const always_ptr& a) : _ptr{ a._ptr } { }
explicit always_ptr(T* p)
{
if (!p) throw std::Exception(); //only way to guarantee this is not null
_ptr = std::shared_ptr<T>(p);
}
T* get() { return _ptr.get(); }
T& operator*() { return *_ptr; }
T* operator->() { return _ptr.get(); }
explicit operator bool() const { return true; } //always true
};
I am using std::shared_ptr in C++11 and I would like to understand if it's better to assign structures of type T in this way:
T a_data;
std::shared_ptr<T> my_pointer(new T);
*my_pointer = a_data;
or like:
memcpy(&my_pointer, data, sizeof(T));
or like:
my_pointer.reset(a_data);
Regards
Mike
They each do a different thing.
1.
T a_data;
std::shared_ptr<T> my_pointer(new T);
*my_pointer = a_data;
Here, a new object (call it n) of type T will be allocated, managed by my_pointer. Then, object a_data will be copy-assigned into n.
2.
memcpy(&my_pointer, a_data, sizeof(T)); // I assume you meant a_data here, not data
That's total nonsense - tha's overwriting the shared_ptr itself with the contents of a_data. Undefined behaviour at its finest (expect a crash or memory corruption).
Perhaps you actually meant my_pointer.get() instead of &my_pointer (that is, you wanted to copy into the object being pointed to)? If that's the case, it can work, as long as T is trivially copyable - which means that it doesn't have non-trivial copy or move ctors, doesn't have non-trivial copy or move assignment operators, and has a trivial destructor. But why rely on that, when normal assignment (*my_pointer = a_data;) does exactly the same for that case, and also works for non-trivially-copyable classes?
3.
my_pointer.reset(a_data);
This normally won't compile as-is, it would need to be my_pointer.reset(&a_data);. That's disaster waiting to happen - you point my_pointer to the automatic (= local) variable a_data and give it ownership of that. Which means that when my_pointer goes out of scope (actually, when the last pointer sharing ownership wiht it does), it will call the deleter, which normally calls delete. On a_data, which was not allocated with new. Welcome to UB land again!
If you just need to manage a dynamically-allocated copy of a_data with a shared_ptr, do this:
T a_data;
std::shared_ptr<T> my_pointer(new T(a_data));
Or even better:
T a_data;
auto my_pointer = std::make_shared<T>(a_data);