Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Could a smart compiler do all the things std::move does without it being part of the language?

Tags:

c++

std

c++11

move

This is a bit theoretical question, but although I have some basic understanding of the std::move Im still not certain if it provides some additional functionality to the language that theoretically couldnt be achieved with supersmart compilers. I know that code like :

{
  std::string s1="STL";
  std::string s2(std::move(s1));
  std::cout << s1 <<std::endl;
} 

is a new semantic behavior not just performance sugar. :D But tbh I guess nobody will use var x after doing std::move(x). Also for movable only data (std::unique_ptr<>, std::thread) couldnt compiler automatically do the move construction and clearing of the old variable if type is declared movable? Again this would mean that more code would be generated behind programmers back(for example now you can count cpyctor and movector calls, with automagic std::moving you couldnt do that ).

like image 885
NoSenseEtAl Avatar asked Dec 11 '25 17:12

NoSenseEtAl


2 Answers

No.

But tbh I guess nobody will use var x after doing std::move(x)

Absolutely not guaranteed. In fact, a decent part of the reason why std::move(x) is not automatically usable by the compiler is because, well, it can't be decided automatically whether or not you intend this. It's explicitly well-defined behaviour.

Also, removing rvalue references would imply that the compiler can automagically write all the move constructors for you. This is definitely not true. D has a similar scheme, but it's a complete failure, because there are numerous useful situations in which the compiler-generated "move constructor" won't work correctly, but you can't change it.

It would also prevent perfect forwarding, which has other uses.

The Committee make many stupid mistakes, but rvalue references is not one of them.

Edit:

Consider something like this:

int main() {
    std::unique_ptr<int> x = make_unique<int>();
    some_func_that_takes_ownership(x);
    int input = 0;
    std::cin >> input;
    if (input == 0)
        some_other_func(x);
}

Owch. Now what? You can't magic the value of "input" to be known at compile-time. This is doubly a problem if the bodies of some_other_func and some_func_that_takes_ownership are unknown. This is Halting Problem- you can't prove that x is or is not used after some_func_that_takes_ownership.

D fails. I promised an example. Basically, in D, "move" is "binary copy and don't destruct the old". Unfortunately, consider a class with, say, a pointer to itself- something you will find in most string classes, most node-based containers, in designs for std::function, boost::variant, and lots of other similar handy value types. The pointer to the internal buffer will be copied but oh noes! points to the old buffer, not the new one. Old buffer is deallocated - GG your program.

like image 61
Puppy Avatar answered Dec 14 '25 07:12

Puppy


It depends on what you mean by "what move does". To satisfy your curiosity, I think what you're looking to be told about the existence of Uniqueness Type Systems and Linear Type Systems.

These are types systems that enforce, at compile-time (in the type system), that a value only be referenced by one location, or that no new references be made. std::unique_ptr is the best approximation C++ can provide, given its rather weak type system.

Let's say we had a new storage-class specifier called uniqueref. This is like const, and specifies that the value has a single unique reference; nobody else has the value. It would enable this:

int main()
{
    int* uniqueref x(new int); // only x has this reference

    // unique type feature: error, would no longer be unique
    auto y = x; 

    // linear type feature: okay, x not longer usable, z is now the unique owner
    auto z = uniquemove(x);

    // linear type feature: error: x is no longer usable
    *x = 5;
}

(Also interesting to note the immense optimizations that can be taking, knowing a pointer value is really truly only referenced through that pointer. It's a bit like C99's restrict in that aspect.)

In terms of what you're asking, since we can now say that a type is uniquely referenced, we can guarantee that it's safe to move. That said, move operates are ultimately user-defined, and can do all sorts of weird stuff if desired, so implicitly doing this is a bad idea in current C++ anyway.

Everything above is obviously not formally thought-out and specified, but should give you an idea of what such a type system might look like. More generally, you probably want an Effect Type System.

But yes, these ideas do exist and are formally researched. C++ is just too established to add them.

like image 44
GManNickG Avatar answered Dec 14 '25 09:12

GManNickG