В этом случае есть ошибка:
const int& foo() {
const int x = 0;
return x;
}
и даже
const int& foo() {
const std::pair<int,int> x = {0,0};
return x.first;
}
, но не это:
const int& foo() {
const std::array<int,1> x = {0};
return x[0];
}
и (что не удивительно) не это:
const int& foo() {
const std::vector<int> x = {0};
return x[0];
}
В частности, в случае std::vector
я получаю, что это предупреждение было бы довольно хитрым, поскольку для компилятора не очевидно, что const int&
, возвращаемый std::vector<int>::operator[](size_t) const
, является ссылкой навременный характер.Я на самом деле немного удивлен тем, что std::array
не дает сбоя, хотя, так как этот похожий случай действительно дает мне ошибку:
struct X {
int x[0];
};
const int& foo() {
X x;
return x.x[0];
}
Есть ли у любого из популярных компиляторов предупреждение / ошибка, которая можетпоймать эти случаи?Я мог бы представить себе консервативную версию, которая предупреждала бы о возвращении ссылки, полученной из вызова функции-члена во временном режиме.
Я споткнулся об этом с помощью чего-то вроде следующего, в котором я встроил цепочку вызовов, но поскольку C ++ позволяет назначать локальные данные для const&
, подробная версия работает, в то время как внешне идентичная версия сразу удаляет временную, оставляя висящую ссылку:
#include <iostream>
struct A {
int x = 1234;
A() { std::cout << "A::A " << this << std::endl; }
~A() { x = -1; std::cout << "A::~A " << this << std::endl; }
const int& get() const { return x; }
};
struct C {
C() { std::cout << "C::C " << this << std::endl; }
~C() { std::cout << "C::~C " << this << std::endl; }
A a() { return A(); }
};
int foo() {
C c;
const auto& a = c.a();
const auto& x = a.get();
std::cout << "c.a(); a.get() returning at " << &x << std::endl;
return x;
}
int bar() {
C c;
const int& x = c.a().get();
std::cout << "c.a().get() returning at " << &x << std::endl;
return x;
}
int main() {
std::cout << foo() << std::endl;
std::cout << bar() << std::endl;
}
, которая выводит
C::C 0x7ffeeef2cb68
A::A 0x7ffeeef2cb58
c.a(); a.get() returning at 0x7ffeeef2cb58
A::~A 0x7ffeeef2cb58
C::~C 0x7ffeeef2cb68
1234
C::C 0x7ffeeef2cb68
A::A 0x7ffeeef2cb58
A::~A 0x7ffeeef2cb58
c.a().get() returning at 0x7ffeeef2cb58
C::~C 0x7ffeeef2cb68
-1