1
#include <iostream>
#include <utility>
int main()
{
    double* ptr;
    {
        double temp = 5.5;
        ptr = new double(std::move(temp));
    }   // temp dies here
    std::cout << *ptr << "\n";
    delete ptr;
}

I know this works. But my point is whether this "5.5" rvalue is gonna be directly transferred to the same but dynamically allocated address? That is, does ptr still point to temp even when temp is no longer in scope?

Let's say it is a huge array we want to move from short-term local range to longer-term storage and later we decide when the variable dies.

More explanations:

Suppose we have address A located in memory. It is going to die in a while but before it dies we are making a cool trick and lock this same A address so that it will not die. Thus we did not have to copy stuff to keep it alive. We just locked it. Is that possible in c++?

anatolyg
  • 26,506
  • 9
  • 60
  • 134
reconn
  • 371
  • 3
  • 9
  • 1
    No, if the address is on the stack, using it will be invalid after function returns. – Erik Alapää Mar 28 '17 at 08:34
  • _Thus we did not have to copy to stuff to keep it alive._ .. Much like a `static` local variable, or a `static` global? – txtechhelp Mar 28 '17 at 08:36
  • 1
    `std::move` on `double` does nothing, and you finally just do a copy. – Jarod42 Mar 28 '17 at 08:36
  • 1
    A powerful gun would be to use stackful coroutines, extremely powerful for some use cases: http://stackoverflow.com/questions/28977302/how-do-stackless-coroutines-differ-from-stackful-coroutines. You can even do it with ugly macros in old-skool C: http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html – Erik Alapää Mar 28 '17 at 08:37
  • You either control lifetime of variable (allocate on heap), or designate control over lifetime of variable to compiler (allocate on stack). Is it reasonable to try to interfere with lifetime of variable, after you designated control over its lifetime to compiler ? – Andrew Kashpur Mar 28 '17 at 08:41
  • The answer is no, this is not possible. – Galik Mar 28 '17 at 09:00

2 Answers2

2

C++ doesn't support it directly. If the object goes out of scope, its lifetime ends, and any pointers remaining to that object are invalid (i.e. dereferencing them invokes undefined behavior).

However, this is not really what goes on in the code:

double* ptr;
{
    double temp = 5.5;
    ptr = new double(std::move(temp));
}   // temp dies here

Here std::move is a no-op (does nothing), and the code is equivalent to the more straightforward variant

double* ptr;
{
    double temp = 5.5;
    ptr = new double(temp);
}   // temp dies here

The double object is dynamically allocated, and initialized with 5.5; nothing special here.

But what if you have a huge array instead of one double object? Then, you are probably using std::vector or std:valarray, and their data elements are always allocated dynamically anyway. Then, it makes sense to use std::move like in the example, and it has just the right behavior:

std::vector<double> values;
{
    std::vector<double> temp;
    // fill the temp array
    if (... want to extend life time of temp ...)
    {
        values = std::move(temp);
    }
}   // temp dies here
// now 'values' is either empty or holds the temp values

Alternatively, if you are using std::array or the built-in array type, you should copy your values (cannot move).

anatolyg
  • 26,506
  • 9
  • 60
  • 134
0

From C++ reference - std::move

std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object.

In particular, std::move produces an xvalue expression that identifies its argument t. It is exactly equivalent to a static_cast to an rvalue reference type.

So what is xvalue, rvalue ...?

From C++ reference - value_category

The programming language CPL was first to introduce value categories for expressions: all CPL expressions can be evaluated in "right-hand mode", but only certain kinds of expression are meaningful in "left-hand mode". When evaluated in right-hand mode, an expression is regarded as being a rule for the computation of a value (the right-hand value, or rvalue). When evaluated in left-hand mode an expression effectively gives an address (the left-hand value, or lvalue). "Left" and "Right" here stood for "left of assignment" and "right of assignment".

C++11

With the introduction of move semantics in C++11, value categories were redefined to characterize two independent properties of expressions[5]:

has identity: it's possible to determine whether the expression refers to the same entity as another expression, such as by comparing addresses of the objects or the functions they identify (obtained directly or indirectly);

can be moved from: move constructor, move assignment operator, or another function overload that implements move semantics can bind to the expression.

In C++11, expressions that:

  • have identity and cannot be moved from are called lvalue expressions;
  • have identity and can be moved from are called xvalue expressions;
  • do not have identity and can be moved from are called prvalue ("pure rvalue") expressions;
  • do not have identity and cannot be moved from are not used[6].

The expressions that have identity are called "glvalue expressions" (glvalue stands for "generalized lvalue"). Both lvalues and xvalues are glvalue expressions.

The expressions that can be moved from are called "rvalue expressions". Both prvalues and xvalues are rvalue expressions.

  • The temp (double) has "identity".
  • The temp (double) can not "be moved from",
    because it's missing "move constructor, move assignment operator, or another function overload that implements move semantics"

So just the value will be used to construct new variable.

Community
  • 1
  • 1
Robert Andrzejuk
  • 5,076
  • 2
  • 22
  • 31