【问题标题】:Understanding this behaviour (r-value reference)了解这种行为(r 值参考)
【发布时间】:2021-06-04 19:54:05
【问题描述】:

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

#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。
  • @AyxanHaqverdili 我的意思是,你是对的。但是由于我无法检查是否是UB,所以我希望有人指出它是否真的是。
  • 您可以使用-fsanitize=address -fsanitize=undefined 了解基本概念。然后使用一个真正的调试器 - printf 查看何时调用构造函数/析构函数。
  • 这段代码实际上定义良好 (1) 创建了一个临时的std::string,它用字符串文字"hello" 初始化。 (2) 对该临时文件的引用被传递给changeSomething()。 (3) changeSomething() 改变临时变量,并返回对它的引用。 (4) 控制权返回main(),并且返回的引用(指临时)用于初始化s - 这是通过复制(修改的)临时发生的 (5) 临时停止在结束时存在表达式/语句。 (6) 在下一条语句中输出s

标签: c++ visual-studio c++11


【解决方案1】:

这不是 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 上查看。

【讨论】:

  • Noisy() 在哪里调用?
  • @Norhther 当您将"Hello" 传递给changeSomething 时,会创建一个Noisy 类型的临时对象。这是调用构造函数的地方。
  • 哦,我明白了。谢谢!
猜你喜欢
  • 2014-02-07
  • 2021-05-07
  • 1970-01-01
  • 2012-11-22
  • 2022-06-21
  • 2017-10-05
  • 2013-07-10
  • 2012-01-24
  • 2019-02-15
相关资源
最近更新 更多