Namaran

Code daily. Without assist.

2026-09-20

loud.cpp

#include <iostream>
#include <string>

const std::string& loud(const std::string& s) {
    return s + "!!!";
}

int main() {
    const std::string& msg = loud("hello");
    std::cout << msg << "\n";
}

このコードはコンパイルできません。何が問題で、どう直せばよいでしょうか?

Answer

s + "!!!"loudの中で作られる一時オブジェクトです。一時オブジェクトは(参照に直接束縛されて寿命が延長される場合を除き)それを作った式の終わりで破棄されますが、ここではreturn文の式自体がその一時オブジェクトを作った式なので、loudから戻った時点でその文字列はもう存在しません。つまりloudは、呼び出し元に渡る前に破棄が確定しているダングリング参照(存在しないオブジェクトを指す参照)を返していることになります。これは名前付きのローカル変数への参照を返す典型的なバグと本質的に同じもので、対象が「名前のない一時オブジェクト」なだけです。GCCはこの形の危険な参照を既定の警告(エラー扱い)で検出するため、実際にこのコードはコンパイルが通りません。関数が新しい文字列を作って返すなら、参照ではなく値として返すべきです。値で返せば、C++17以降の保証されたコピー省略により余計なコピーも作られません:

#include <iostream>
#include <string>

std::string loud(const std::string& s) {
    return s + "!!!";
}

int main() {
    const std::string& msg = loud("hello");
    std::cout << msg << "\n";
}