了解此行为r 值参考

问题描述

我正在使用以下代码进行一些测试:

#include <iostream>
#include <string>
using namespace std;

string& changeSomething(string&& s) {
    s[0] = 'a';
    return s;
}

int main() {
    string s = changeSomething("hello");
    cout << s << endl;
}

这里我将一个右值引用传递给函数,并返回一个对对象的引用。这里的问题是我认为这会给 UB,因为我将 r 值传递给函数并且它没有分配内存地址,但是输出

你好

这里有我遗漏的东西吗?

解决方法

这不是UB。临时对象直到表达式结束才会被销毁,您可以在同一表达式中复制它。要获得基本的第一个想法,您可以使用 -fsanitize=address -fsanitize=undefined。它并不完美,但有帮助。为了更准确地了解何时调用构造函数/析构函数,您可以从中打印一些内容:

#include <cstdio>

struct Noisy {
  char const* data;
  Noisy(char const* ch) : data{ch} { std::puts("Noisy()"); }
  Noisy(Noisy const& oth) : data{oth.data} { std::puts("Noisy(Noisy const&)"); }
  ~Noisy() { std::puts("~Noisy()"); }
};

Noisy& changeSomething(Noisy&& s) { return s; }

int main() {
  Noisy s = changeSomething("Hello");
  std::puts(s.data);
}

输出为:

Noisy()
Noisy(Noisy const&)
~Noisy()
Hello
~Noisy()

可以看到复制是在销毁前完成的,所以销毁后什么也访问不了。在 Compiler Explorer 上查看。