这里是我目前正在研究的玩具的一个例子
class Foo
{
private:
std::string s;
std::vector<std::string> v;
public:
// Foo constructors and other big 3
std::string const& strmember() const;
std::vector<std::string> const& vecmember() const;
std::vector<std::string>& vecmember();
};
到目前为止一切都很好。要求是这样的,我必须添加重载并更改Foo
的内线,如下所示
class Foo
{
private:
std::u16string ssname;
std::vector<std::u16string> vvname;
public:
// Foo constructors and other big 3
std::string const& strmember() const;
std::vector<std::string> const& vecmember() const;
std::vector<std::string>& vecmember();
std::u16string const& strmember(int) const;
std::vector<std::u16string> const& vecmember(int) const;
std::vector<std::u16string>& vecmember(int);
};
我必须保留旧成员并为新成员添加重载,以使旧客户端不会中断。执行适当的字符转换,以便将较早的构造函数委派给新的构造函数,并根据新设计更改提供的成员。
如下实施这些成员
std::string const& Foo::strmember() const
{
const auto& name = char_convert(ssname);
return name;
}
std::vector<std::string>& Foo::vecmember()
{
return vecmember();
}
std::vector<std::string>& Foo::vecmember()
{
std::vector<std::string> result;
std::transform(vvname.begin(),vvname.end(),std::back_inserter(result),[] (const std:u16string& in) -> std::string
{
return char_convert(in);
});
return result;
}
std::u16string const& Foo::strmember(int) const
{
return ssname;
}
std::vector<std::u16string> const& Foo::vecmember(int) const
{
return vvname;
}
std::vector<std::u16string>& Foo::vecmember(int)
{
return vvname;
}
[当我尝试编译更改的代码时,编译器会显示以下警告和错误消息
error: reference to local variable ‘result’ returned [-Werror=return-local-addr]
std::vector<std::string> result;
^~~~~~
foo.cpp: In member function ‘const string& foo::strmember() const’:
foo.cpp: error: function returns address of local variable [-Werror=return-local-addr]
return name;
^~~~
foo.cpp: note: declared here
const auto& name = char_convert(ssname);
^
cc1plus: all warnings being treated as errors
我该如何解决这个问题?我无法更改界面,因为它可能会破坏单元测试和客户端。
我如何提供vecmember()
和strmember()
函数的转换器和访问器版本?
const auto& name = char_convert(ssname); // Really bad (undefined behaviour)
您正在将引用绑定到右值。该语句之后将销毁std::string
返回的临时char_convert()
。因此,甚至在name
函数返回strmember()
之前,它们都是悬空的。您可能应该改写(复制初始化):
auto name = char_convert(ssname); // Better
关于返回对局部变量的const
引用的函数,您应该按值返回而不是修复错误(编译器将能够在需要时对返回的局部变量执行复制删除)。
关于最后一个返回非const引用的函数,我认为使用代理类可能会过大(不过,这当然取决于您的用例)。一种更简单的方法可能是编写一个似乎需要的setter函数。
但是,无论您编写setter还是使用代理,由于它是错误的并调用未定义的行为,因此将破坏与旧代码的兼容性。