Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
So there are copy semantics, move semantics and maybe more semantics that I don't know of. I have read articles about both but I still do not really get have a good definition of "semantics". As the name suggests, move semantics have something to do with moving things but why is it called move semantics?
The more clear version: What is the meaning of semantics in the context of programming? Example: Move and copy semantics.
Semantics basically means "the meaning of".
It may help to look at a more familiar case to explain the term.
Consider:
int a = 3;
int b = 5;
int c = a + b;
The value of a + b is 8 because the semantics of the + operator is to take the numerical sum of its operands.
Now consider this:
std::string a = "hello";
std::string b = "world";
std::string c = a + b;
The value of a + b is "helloworld" because the semantics of the + operator is to concatenate its operands.
The + operator, when used with std::string is said to have different semantics from when it is used with numerical types.
It has a different meaning.
Now consider copy and move semantics:
std::string a = "hello";
std::string b;
b = a; // b receives a copy of a's value
b = std::string("hello"); // the temporary value is moved into b
We have the same operator = which has a different meaning in different situations. Again we say is has different semantics.
The first case has copy semantics and the second case has move semantics.
The word semantics is used to describe an underlying meaning of something.
You can say that an operation has the move semantics when it transfers an object state from one object to another. In reality of course what happens is some pointers are probably copied over and that's it, but semantically your object has been moved.
Another example is the ownership transfer, when the most important thing that is moved is the responsibility (i.e. the promise to release some resource). In that case from the computational point of view pretty much nothing happens, but semantically the ownership is transferred.
The same goes for copy semantics: you can say that passing an object to a function has copy semantics i.e. your object would be duplicated and the function will get a standalone copy with its own lifetime.
Another side of the coin is the syntax which is how you describe what you want following the rules of the language.
C++ has really flexible syntax - overloading operators, user-defined conversions, macros and what not, so almost any desirable semantics can be attached to any particular syntax.
Semantics is about the meaning of something. move-semantic is about the meaning of moving objects. Specifically, in this context, it tells you what it means to move something in C++.
The semantic of moving is all about everything that is involved during a move operation.
read move-semantic as: what does it mean, what are the implications (and how do you achieve it ) of moving an object in a C++ program?
The following is a good answer that might help: What are move semantics?
Related
Item 29 from Effective Modern C++, Scott Meyers lists three scenarios where move semantics don't improve code's performance,
[…] move semantics do you no good:
No move operations: The object to be moved from fails to offer move operations […]
Move not faster: […] move operations that are no faster than its copy operations.
Move not usable: The context […] requires a move operation that emits no exceptions, but that operation isn't declared noexcept.
which are all clearly explained in the preceding pages, and then adds another one
[…] another scenario where move semantics offers no efficiency gain:
Source object is lvalue: With very few exceptions (see e.g. Item 25) only rvalues may be used as the source of a move operation.
(Item 25 is titled Use std::move on rvalue references and std::forward on universal references, but I don't see how it is related to the bullet point that cross-references it.)
After this, the text essentially goes back to summarizing the item, with no further reference to that fourth bullet point.
What does that bullet point refer to?
As far as I understand move semantics, even if I want to move from an lvalue, say x, I still need to cast it to an rvalue via std::move(x) (or an equivalent static_cast), so I'm technically still moving from an rvalue (specifically an xvalue in this case), not an lvalue.
So I'd be tempted to say that an lvalue cannot be the source object of a move operation.
What am I missing about this topic?
The term lvalue refers to somehow “named” values, i.e., entities having multiple references. Move semantics don’t really apply to them as you shouldn’t “steal” the representation of something which may be referred to elsewhere. That is, if the source object is an lvalue you simply never move! So, move construction doesn’t provide a benefit here. In fact, lvalues don’t bind willingly to rvalue references - you’d beed to force that binding, e.g., by using std::move().
Essentially, your point is entirely correct: an lvalue cannot be the source of a move operation - and hence move operations don’t provide a benefit where lvalues are involved.
As an example: You have a class T with a move constructor. You have a function returning an object of type T, and you try to make it faster by returning in r-value. Now if you start with
T x;
x.a = ...;
x.b = ...;
x.c = ...;
return x;
then an object x will be constructed, a new unnamed object will be created by the return statement, then x is destructed, then the return value is moved. And eventually the caller will call the destructor for the moved result. So you have two constructors, two destructors, no savings.
If you start with
T x(a, b, c);
return x;
then you have the same problem, two constructors and destructors, no savings. To actually save anything, you need to write
return T(a, b, c);
or return the return value of another function returning an object.
I have been searching for this matter on SO and other sources but I couldn't wrap my head around this issue. Using resouces of rvalues and xvalues somewhat new to C++ (with C++11).
Now, do we - C programmers - miss something here? Or there is a corresponding technique in C to benefit from these resource efficiency?
EDIT: This quesiton is not opinion based whatsoever. I just couldn't describe my question. What I am asking is that whether or not there is a corresponding technique in c.
Of course, there is a similar technique in C. We have been doing "move semantics" in C for ages.
Firstly, "move semantics" in C++ is based on a bunch of overload resolution rules that describe how functions with rvalue reference parameters behave during overload resolution. Since C does not support function overloading, this specific matter is not applicable to C. You can still implement move semantics in C manually, by writing dedicated data-moving functions with dedicated names and explicitly calling them when you want to move the data instead of copying it. E.g, for your own data type struct HeavyStruct you can write both a copy_heavy_struct(dst, src) and move_heavy_struct(dst, src) functions with appropriate implementations. You'll just have to manually choose the most appropriate/efficient one to call in each case.
Secondly, the primary purpose of implicit move semantics in C++ is to serve as an alternative to implicit deep-copy semantics in contexts where deep copying is unnecessarily inefficient. Since C does not have implicit deep-copy semantics, the problem does not even arise in C. C always performs shallow copying, which is already pretty similar to move semantics. Basically, you can think of C as an always-move language. It just needs a bit of manual tweaking to bring its move semantics to perfection.
Of course, it is probably impossible to literally reproduce all features of C++ move semantics, since, for example, it is impossible to bind a C pointer to an rvalue. But virtually everything can be "emulated". It just requires a bit more work to be done explicitly/manually.
I don't believe it's move semantics that C is missing. It's all the C++ functionality leading up to move semantics that is "missing" in C. Since you can't do automatic struct copies that call functions to allocate memory, you don't have a system for automatically copy complex and expensive data structures.
Of course, that's the intention. C is a more light-weight language than C++, so the complexity of creating custom copy and assignment constructors is not meant to be part of the language - you just write code to do what needs to be done as functions. If you want "deep copy", then you write something that walks your data structure and allocates memory, etc. If you want shallow copy, you write something that copies the pointers in the data structure to the other one (and perhaps setting the source ones to NULL) - just like a move semantics constructor does.
And of course, you only need L and R value in C (it is either on the left or the right of an = sign), there are no references, and clearly no R value references. This is achieved in C by using address of (turning things into pointers).
So it's not really move semantics that C is missing, it's the complex constructors and assignment operators (etc) that comes with the design of the C++ language that makes move semantics a useful thing in that language. As usual, languages evolve based on their features. If you don't have feature A, and feature B depends on feature A being present, you don't "need" feature B.
Of course, aside from exception handling and const references [and consequently R value references in C++11, which is esentially a const reference that you are allowed to modify], I don't think there is any major feature in C++ that can't be implemented through C. It's just a bit awkward and messy at times (and will not be as pretty syntactically, and the compiler will not give you neat error messages when you override functions the wrong way, you'll need to manually cast pointers, etc, etc). [After stating something like this, someone will point out that "you obviously didn't think of X", but the overall statement is still correct - C can do 99.9% of what you would want to do in C]
No. You have to roll-your-own but like other features of C++ (e.g. polymorphism) you can effect the same semantics but with more coding:
#include<stdlib.h>
typedef struct {
size_t cap;
size_t len;
int* data;
} vector ;
int create_vector(vector *vec,size_t init_cap){
vec->data=malloc(sizeof(int)*init_cap);
if(vec->data==NULL){
return 1;
}
vec->cap=init_cap;
vec->len=0;
return 0;
}
void move_vector(vector* to,vector* from){
//This effects a move...
to->cap=from->cap;
to->len=from->len;
free(to->data);
to->data=from->data;//This is where the move explicitly takes place.
//Can't call destroy_vec() but need to make the object 'safe' to destroy.
from->data=NULL;
from->cap=0;
from->len=0;
}
void destroy_vec(vector *vec){
free(vec->data);
vec->data=NULL;
vec->cap=0;
vec->len=0;
}
Notice how in the move_vector() the data is (well…) moved from one vector to another.
The idea of handing resources between objects is common in C and ultimately amounts to 'move semantics'. C++ just formalised that, cleaned it up and incorporated it in overloading.
You may well even have done it yourself and don't realise because you didn't have a name for it. Anywhere where the 'owner' of a resource is changed can be interpreted as 'move semantics'.
C doesn't have a direct equivalent to move semantics, but the problems that move semantics solve in c++ are much less common in c:
As c also doesn't have copy constructors / assignment operators, copies are by default shallow, whereas in c++ common practice is to implement them as deep copy operations or prevent them in the first place.
C also doesn't have destructors and the RAII pattern, so transferring ownership of a resource comes up less frequently.
The C equivalent to C++ move semantics would be to pass a struct by value, and then to proceed with throwing away the original object without destructing it, relying on the destruction of the copy to be correct.
However, this is very error prone in C, so it's generally avoided. The closest to move semantics that we actually do in C, is when we call realloc() on an array of structs, relying on the bitwise copy to be equivalent to the original. Again, the original is neither destructed nor ever used again.
The difference between the C style copy and C++ move semantics is, that move semantics modify the original, so that its destructor may safely be invoked. With the C bitwise copy approach, we just forget about the contents of the original and don't call a destructor on it.
These more strict semantics make C++ move semantics much easier and safer to use than the C style copy and forget. The only drawback of C++ move semantics is, that it's slightly slower than the C style copy and forget approach: Move semantics copy by element rather than bitwise, then proceed to modify the original, so that the destructor becomes a semantical noop (nevertheless, it's still called). C style copy and forget replace all this by a simple memcpy().
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
Is the following code safe?
struct Foo {
Foo bar() { return *this; }
} foo;
foo = std::move(foo).bar(); // is this safe?
I'm wondering if calling methods on an rvalue is safe.
In general, calling a function on an rvalue is no more or less safe than calling it on an lvalue.
As for your specific code, no movement actually happens. std::move(foo) converts it into an rvalue, which is irrelevant to the call to Foo::bar since it doesn't care whether this is an lvalue or an rvalue. bar will return a copy of foo, which will then be copied back into foo.
The same thing would have happened if you hadn't used std::move at all. std::move doesn't actually move anything; it simply converts it into an rvalue which can participate in a move operation.
Your real question is this: for any type T which is moveable, is this legal:
T t;
t = T(std::move(t));
The answer is... maybe. The state of a moved-from object is exactly what the writer of T chooses for it to be. For most standard library types, it will be "valid-but-unspecified". This means that you can use functions that don't require preconditions, that will work regardless of the current state.
Move assignment is usually such a function, so that will generally work. Will it work for all types? There is nothing which guarantees that it will. It depends on how move support is implemented for each type. Some user-defined types can't achieve even a "valid-but-unspecified" state, which means the only thing you're allowed to do with a moved-from object is destroy it.
It all depends on how users choose to work. However, I would say that a type for which t = T(std::move(t)) does not work (that is, yields undefined behavior) would be a very ill-behaved type.
Not super safe, it is sometimes hard to break down, if it's just for a simple program/game it should be fine, I would recommend that you use a more secure code for a big program :)
Overall it's not going to be too bad if it breaks.
What I mean by super safe is that it can't handle a break, if you decide to use a function of a standard way of doing it (e.g: using Struct like you have)
Sorry I can't supply as much information as I can, I'm newish to struct
if anyone wants to edit my answer they can.
Thanks,
~Coolq
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
The community reviewed whether to reopen this question 8 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I was coding up a C++ class today, and I wrote a function that took an argument as a reference rather than a pointer, something I rarely ever do. I've always passed by pointers. So I was about to change it back, and then I realized - I have no idea if I should, or if it even matters.
So I turn to you guys. I have three ways of passing parameters about:
//1: By pointer
Object* foo(Object* bar) {…}
//2: By reference
Object& foo(Object& bar) {…}
//3: By value (just for completeness)
Object foo(Object bar) {…}
Assuming #3's out for performance reasons (yes, I know compilers have gotten pretty good at this, but still), the other two are more or less equivalent.
So: What's the "best" method? Pointers? References? Some combination of the two? Or does it even matter? Technical reasons are the best, but stylistic reasons are just as good.
Update: I've accepted YeenFei's answer, since it deals with the difference that clinched it for me (even if I then pointedly ignored his advice - I like having NULL as an option...). But everyone made good points - especially GMan (in the comments), and Nemo, in the answer dealing with performance and passing by value. If you're here for answers, check them all!
I would suggest to pass your argument by reference if it is expected to be valid. This would be a by-design optimization and save you from defensive programming.
Reference cannot be null while pointer can.
If you are dealing with pointer, you will need to verify whether given pointer is valid (non-null) regardless it is in raw form or wrapped in managed container (shared_ptr), before using them.
So I am going to make the case for choice #3. Consider the following code:
struct Foo {
int x;
int y;
};
Foo
add(Foo a, Foo b)
{
Foo result;
result.x = a.x + b.x;
result.y = a.y + b.y;
return result;
}
Foo
add2(Foo &a, Foo &b)
{
Foo result;
result.x = a.x + b.x;
result.y = a.y + b.y;
return result;
}
Try examining the generated assembly. Notice how add is almost entirely register operations, nicely scheduled. Notice how add2 is lots of memory accesses without any reordering.
I wrote a main that called each of these functions 10 billion times. Result? add took 22 seconds, while add2 took 26 seconds. Even for this trivial example, that's 10-20% better performance for the pass-by-value version.
OK, so the structure is trivial. But so is the function. The more complex the function, the more likely the pass-by-value version is to be faster, because the compiler knows that the two arguments do not "overlap". This is a huge benefit to optimization.
Of course, this decision should primarily be based on the semantics of the function: Do you need NULL to be a legal value? If so, obviously you need a pointer. Do you need to modify the objects? Then use a pointer or a reference.
But if you do not need to modify the objects, prefer to pass them by value unless the objects are large and/or have a non-trivial copy constructor (e.g. std::string). If by-value really is too slow, pass by reference-of-const or pointer-to-const.
But do not underestimate the potential speed advantages of passing by value, which derive from the advantages of registers vs. memory and instruction reordering. And note that these advantages become more pronounced with every generation of CPU.
Passing by pointer and by reference are really the same, except in syntax. I prefer passing by pointer, because it makes things explicit:
Object bar;
ptr_foo(&bar); // bar may change
ref_foo(bar); // can bar change? Now I need to go look at the prototype...
val_foo(bar); // bar cannot change. (Unless you use references here and there)
The only technical preference between passing values and pointers, as you have touched on is if the class is large enough to make its passing slow.
References any day, if you're designing everything yourself. Idiomatic modern C++ should almost never have raw pointers sticking out anywhere. Dynamically allocated objects should travel in resource managing containers (shared_ptr or unique_ptr, or weak_ptr if applicable), but for most operations passing by (const) reference is the primary way to pass arguments that need to be modified or that are of a heavy-weight type. Don't forget that passing by value may be a viable option if you have movable types.
Use:
const reference if the object is not modified
pointer if the object is modified or can be null
value if the object is small and you care about performance or if you need a copy of the object inside the function. This allows the compiler to pick the best way to copy/move the argument.
std::unique_ptr if ownership is transferred to the function.
You can take a look at https://www.boost.org/doc/libs/1_51_0/libs/utility/call_traits.htm library, it converts the type to the best arguments type automatically.
A problem of "value types" with external resources (like std::vector<T> or std::string) is that copying them tends to be quite expensive, and copies are created implicitly in various contexts, so this tends to be a performance concern. C++0x's answer to this problem is move semantics, which is conceptionally based on the idea of resource pilfering and technically powered by rvalue references.
Does D have anything similar to move semantics or rvalue references?
I believe that there are several places in D (such as returning structs) that D manages to make them moves whereas C++ would make them a copy. IIRC, the compiler will do a move rather than a copy in any case where it can determine that a copy isn't needed, so struct copying is going to happen less in D than in C++. And of course, since classes are references, they don't have the problem at all.
But regardless, copy construction already works differently in D than in C++. Generally, instead of declaring a copy constructor, you declare a postblit constructor: this(this). It does a full memcpy before this(this) is called, and you only make whatever changes are necessary to ensure that the new struct is separate from the original (such as doing a deep copy of member variables where needed), as opposed to creating an entirely new constructor that must copy everything. So, the general approach is already a bit different from C++. It's also generally agreed upon that structs should not have expensive postblit constructors - copying structs should be cheap - so it's less of an issue than it would be in C++. Objects which would be expensive to copy are generally either classes or structs with reference or COW semantics.
Containers are generally reference types (in Phobos, they're structs rather than classes, since they don't need polymorphism, but copying them does not copy their contents, so they're still reference types), so copying them around is not expensive like it would be in C++.
There may very well be cases in D where it could use something similar to a move constructor, but in general, D has been designed in such a way as to reduce the problems that C++ has with copying objects around, so it's nowhere near the problem that it is in C++.
I think all answers completely failed to answer the original question.
First, as stated above, the question is only relevant for structs. Classes have no meaningful move. Also stated above, for structs, a certain amount of move will happen automatically by the compiler under certain conditions.
If you wish to get control over the move operations, here's what you have to do. You can disable copying by annotating this(this) with #disable. Next, you can override C++'s constructor(constructor &&that) by defining this(Struct that). Likewise, you can override the assign with opAssign(Struct that). In both cases, you need to make sure that you destroy the values of that.
For assignment, since you also need to destroy the old value of this, the simplest way is to swap them. An implementation of C++'s unique_ptr would, therefore, look something like this:
struct UniquePtr(T) {
private T* ptr = null;
#disable this(this); // This disables both copy construction and opAssign
// The obvious constructor, destructor and accessor
this(T* ptr) {
if(ptr !is null)
this.ptr = ptr;
}
~this() {
freeMemory(ptr);
}
inout(T)* get() inout {
return ptr;
}
// Move operations
this(UniquePtr!T that) {
this.ptr = that.ptr;
that.ptr = null;
}
ref UniquePtr!T opAssign(UniquePtr!T that) { // Notice no "ref" on "that"
swap(this.ptr, that.ptr); // We change it anyways, because it's a temporary
return this;
}
}
Edit:
Notice I did not define opAssign(ref UniquePtr!T that). That is the copy assignment operator, and if you try to define it, the compiler will error out because you declared, in the #disable line, that you have no such thing.
D have separate value and object semantics :
if you declare your type as struct, it will have value semantic by default
if you declare your type as class, it will have object semantic.
Now, assuming you don't manage the memory yourself, as it's the default case in D - using a garbage collector - you have to understand that object of types declared as class are automatically pointers (or "reference" if you prefer) to the real object, not the real object itself.
So, when passing vectors around in D, what you pass is the reference/pointer. Automatically. No copy involved (other than the copy of the reference).
That's why D, C#, Java and other language don't "need" moving semantic (as most types are object semantic and are manipulated by reference, not by copy).
Maybe they could implement it, I'm not sure. But would they really get performance boost as in C++? By nature, it don't seem likely.
I somehow have the feeling that actually the rvalue references and the whole concept of "move semantics" is a consequence that it's normal in C++ to create local, "temporary" stack objects. In D and most GC languages, it's most common to have objects on the heap, and then there's no overhead with having a temporary object copied (or moved) several times when returning it through a call stack - so there's no need for a mechanism to avoid that overhead too.
In D (and most GC languages) a class object is never copied implicitly and you're only passing the reference around most of the time, so this may mean that you don't need any rvalue references for them.
OTOH, struct objects are NOT supposed to be "handles to resources", but simple value types behaving similar to builtin types - so again, no reason for any move semantics here, IMHO.
This would yield a conclusion - D doesn't have rvalue refs because it doesn't need them.
However, I haven't used rvalue references in practice, I've only had a read on them, so I might have skipped some actual use cases of this feature. Please treat this post as a bunch of thoughts on the matter which hopefully would be helpful for you, not as a reliable judgement.
I think if you need the source to loose the resource you might be in trouble. However being GC'ed you can often avoid needing to worry about multiple owners so it might not be an issue for most cases.