It is not a cast. std::pair<const std::string, ...> and std::pair<std::string,...> are different types, although there is an implicit conversion. So a temporary is implicitly created and bound to the const reference. So not only there is a copy, you have a reference to an object that is destroyed at end of scope when you might expect it to live further.
I guess this is one of the reasons, why I don't use C++. Temporaries is a topic, where C++ on one side and me and C on the other side has had disagreements in the past. Why does changing the type even create another object at all? Why does it allocate? Why doesn't the optimizer use the effective type to optimize that away?
> Why does changing the type even create another object at all?
There's no such thing as "changing the type" in c++.
Function returns an object type A, your variable is of type B, compiler tries to see if there is a conversion of the value of type A to a new value of type B
Each entry in the map will be copied. In C++, const T& is allowed to bind to a temporary object (whose lifetime will be extended). So a new pair is implicitly constructed, and the reference binds to this object.
> Both Microsoft and Google seem to do it just fine
Microsoft sends me DMARC reports saying "yes, everything was accepted 100%, all good". The delivery logs on our end look good as well. However, they silently drop a large portion of messages with a Hotmail destination.
Yeah, there is a whole layer of Rube Goldberg-esque nonsense between the public Microsoft SMTP servers and the actual destinations that not even the highest levels of their support seem to properly understand.
Like: if you truly want to ensure delivery to an Office 365 tenant, EWS is pretty much the only option. Anything else will have random gaps, even after the tenant themselves have begged everyone they could find to let that particular sender, domain, IP, and everything through no matter what...
A nice way to fix bugs is to make the buggy state impossible to represent. In cases where a bug was caused by some fundamental flaw in the original design, a redesign might be the only way to feel reasonably confident about the fix.
I.e., if I pthread_mutex_init(&some_addr, ...), I cannot then copy the bits from some_addr to some_other_addr and then pthread_mutex_lock(&some_other_addr). Hence not movable.
> Moving a mutex is otherwise non-sensical once the mutex is visible
What does "visible" mean here? In Rust, in any circumstance where a move is possible, there are no other references to that object, hence it is safe to move.
Well, technically if you only have a mutable borrow (it's not your object) then you can't move from it unless you replace it somehow. If you have two such borrows you can swap them, if the type implements Default you can take from one borrow and this replaces it with its default and if you've some other way to make one you can replace the one you've got a reference to with that one, but if you can't make a new one and don't have one to replace it with, then too bad, no moving the one you've got a reference to.
> What does "visible" mean here? In Rust, in any circumstance where a move is possible, there are no other references to that object, hence it is safe to move.
And other than during construction or initialization (of the mutex object, containing object, or related state), how common is it in Rust to pass a mutex by value? If you can pass by value then the mutex isn't (can't) protect anything. I'm struggling to think of a scenario where you'd want to do this, or at least why the inability to do so is a meaningful impediment (outside construction/initialization, that is). I understand Rust is big on pass-by-value, but when the need for a mutex enters the fray, it's because you're sharing or about to share, and thus passing by reference.
Depends on the program, and it can be a very useful tool.
Rust has Mutex::get_mut(&mut self) which allows getting the inner &mut T without locking. Having a &mut Mutex<T> implies you can get &mut T without locks. Being able to treat Mutex<T> like any other value means you can use the whole suite of Rust's ownership tools to pass the value through your program.
Perhaps you temporarily move the Mutex into a shared data structure so it can be used on multiple threads, then take it back out later in a serial part of your program to get mutable access without locks. It's a lot easier to move Mutex<T> around than &mut Mutex<T> if you're going to then share it and un-share it.
Also It's impossible to construct a Mutex without moving at least once, as Rust doesn't guarantee return value optimization. All moves in Rust are treated as memcpy that 'destroy' the old value. There's no way to even assign 'let v = Mutex::new()' without a move so it's also a hard functional requirement.
The tracks on the Gothenburg side have since been removed, so even this workaround would not be possible today (they would have to go to Trelleborg instead).
It is interesting though that when he mentions AI as one of the non-silver bullets, one of the arguments is that the AI models of the time were problem-specific and not easily transferable.
reply