Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

In what way it is a footgun? auto x = ... ; does what I would expect. Copying is usually the default in C++ and that's what I would expect to happen here.

If auto deduced reference types transparently, it would actually be more dangerous.





Copying is a weird default because who said that's even achievable, let alone cheap?

So I guess I depart from you there and thus my issue here is not really about auto


C++ has value semantics, which means that values of user-defined types generally behave like values of built-in types. In this sense, copying is the only logical default. It's just how the language has been designed.

Things are different in Rust because of lifetimes and destructive moves. In this context, copying would be a bad default indeed.

> because who said that's even achievable, let alone cheap?

Nobody said that. The thing is that user-defined types can be anything from tiny and cheap to huge and expensive. A language has to pick one default and be consistent. You can complain one way or the other.


I find passing by value to be sensible, but the allocating part sounds like a bad idea. Passing the value of something doesn't imply making a copy, if the value is never changed, it can be entirely optimized away.

> Passing the value of something doesn't imply making a copy

Yes, languages like Rust can automatically move variables if the compiler can prove that they will not be used anymore. Unfortunately, this is not possible in C++, so the user has to move explicitly (with std::move).


> Unfortunately, this is not possible in C++, so the user has to move explicitly (with std::move).

Honestly why not? A locally used variable sounds to be very much something the compiler can reason about. And a variable only declared in a loop, which is destroyed at the end of each iteration and only read from should be able to be optimized away. I don't know Rust, I mostly write C.


Yes, this could work for simple cases, but this breaks down pretty quickly:

  void checkFoo(const Foo&);
  
  Foo getFoo();
  
  void example() {
    std::vector<Foo> vec;

    Foo foo = getFoo();
    if (checkFoo(foo)) {
      // *We* know that checkFoo() does not store a
      // reference to 'foo' but the compiler does not
      // know this. Therefore it cannot automatically
      // move 'foo' into the std::vector.
      vec.push_back(std::move(foo));
    }
  }
The fundamental problem is that C++ does not track object lifetimes. You would end up with a system where the compiler would move objects only under certain circumstances, which would be very hard to reason about.

Ah, you are right. It theoretically should be able to do it, but even with -flto, there are likely cases, where it doesn't. It is less of a problem with C, since you explicitly tell the compiler, whether you want things to get passed as value or pointer. Also I typically annotate ownership, so it it easy to forget that the compiler doesn't actually knows this. This is a weird limitation, there should be just a parameter attribute to do that.

> It theoretically should be able to do it, but even with -flto, there are likely cases, where it doesn't.

Note that link time optimization only works on a particular binary. What if the function is implemented in a shared library?

> It is less of a problem with C, since you explicitly tell the compiler, whether you want things to get passed as value or pointer.

It works the exact same way in C++, though.


> What if the function is implemented in a shared library

If it is in the public API/ABI of a shared library, than the calling semantics including lifetime and ownership rules are part of the public interface, so of course the compiler can't just change it. You the programmer are responsible for drawing abstraction boundaries and choosing the interface.

> It works the exact same way in C++, though.

Only if write C in C++. The issue here are references, of which the compiler figures out whether this should work like a value or like a pointer. This doesn't exist in C, there the programmer needs to make up its mind and choose. The whole type conversion by making a copy issue also doesn't exist there, because either the type matches or the compiler throws an error.


Maybe I misunderstood, but I thought that you were arguing that with link-time optimization the compiler could see through cases such as the one I have given. As a counterargument, I brought up functions that are implemented in shared libraries, which are essential a blackbox to the compiler.

> The issue here are references, of which the compiler figures out whether this should work like a value or like a pointer.

I'm not sure I understand. A C++ reference always has reference semantics. Can you give an example?


That's exactly what I was about to write!



Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: