考虑

struct A {
    int *ptr;

    A() : ptr(new int()) { }
    A(A &&o) : ptr(o.release()) { }

    ~A() {
        if (ptr) 
            delete ptr;
    }

    int *release() {
        return std::exchange(ptr, nullptr);
    }
};

相当于简单的 std::unique_ptr,那么考虑下面的情况

A make();

void store(int *);

inline A foo() {
    A a = make();
    return FOO(a);
}

void bar() {
    A a = foo();
    store(a.release());
}

FOOstd::move 时编译结果如下(clang 11.0.1, O2)

bar(): # @bar()
  pushq %rax
  movq %rsp, %rdi
  callq make()
  movq (%rsp), %rdi
  callq store(int*)
  popq %rax
  retq

FOO 为空时编译结果如下(条件同上)

bar(): # @bar()
  pushq %rbx
  subq $16, %rsp
  leaq 8(%rsp), %rdi
  callq make()
  movq 8(%rsp), %rdi
  movq $0, 8(%rsp)
  callq store(int*)
  movq 8(%rsp), %rdi
  testq %rdi, %rdi
  je .LBB0_3
  callq operator delete(void*)
.LBB0_3:
  addq $16, %rsp
  popq %rbx
  retq
  movq %rax, %rbx
  movq 8(%rsp), %rdi
  testq %rdi, %rdi
  je .LBB0_6
  callq operator delete(void*)
.LBB0_6:
  movq %rbx, %rdi
  callq _Unwind_Resume

发生什么事了呢,见 Escape analysis hates copy elision

涉及了 NRVO (copy elision), escape analysis