有没有一种方法可以从函数中返回一个新对象或对现有对象的引用
Is there a way to return either a new object or reference to existing object from a function?
我正在尝试编写一个函数,它可以返回对作为第一个参数传递的现有对象的引用(如果它处于正确状态(,也可以使用作为第二个参数传递来的文字创建并返回新对象(默认值(。
如果一个函数不仅可以接受文本,还可以接受另一个现有对象作为第二个(默认(参数,并返回对它的引用,那就更好了
下面是一个琐碎的实现,但它做了很多不必要的工作:
-
如果使用lvalue作为第二个(默认(参数进行调用,则会调用参数的复制构造函数,该构造函数被选择用于返回。理想情况下,应该返回对对象的引用。
-
如果使用literal作为第二个(默认(参数进行调用,它将调用构造函数、复制构造函数和析构函数,即使没有选择第二个参数(默认(进行返回。如果在不调用复制构造函数或析构函数的情况下构造对象并将其作为右值引用返回,效果会更好。
std::string get_or_default(const std::string& st, const std::string& default_st) {
if (st.empty()) return default_st
else return st;
}
有没有一种方法可以更有效地实现这一点,同时对调用者保持简单?如果我是正确的,这需要函数根据函数内部的运行时决定来更改返回类型,但我想不出一个简单的调用方解决方案。
我不能100%确定我理解需求的组合,但:
#include <iostream>
#include <string>
#include <type_traits>
// if called with an rvalue (xvalue) as 2:nd arg, move or copy
std::string get_or_default(const std::string& st, std::string&& default_st) {
std::cout << "got temporaryn";
if(st.empty())
return std::move(default_st); // rval, move ctor
// return std::forward<std::string>(default_st); // alternative
else
return st; // lval, copy ctor
}
// lvalue as 2:nd argument, return the reference as-is
const std::string& get_or_default(const std::string& st,
const std::string& default_st) {
std::cout << "got refn";
if(st.empty()) return default_st;
else return st;
}
int main() {
std::string lval = "lval";
// get ref or copy ...
decltype(auto) s1 = get_or_default("", "temporary1");
decltype(auto) s2 = get_or_default("", std::string("temporary2"));
decltype(auto) s3 = get_or_default("", lval);
std::cout << std::boolalpha;
std::cout << std::is_reference_v<decltype(s1)> << "n";
std::cout << std::is_reference_v<decltype(s2)> << "n";
std::cout << std::is_reference_v<decltype(s3)> << "n";
}
输出:
got temporary
got temporary
got ref
false
false
true
编辑:在OP测试后,制作了一个稍微更通用的版本。它可以使用lambda,如auto empty_check = [](const std::string& s) { return s.empty(); };
来测试第一个参数是否为空。
template<typename T, typename F>
T get_or_default(const T& st, T&& default_st, F empty) {
if(empty(st)) return std::move(default_st);
// return std::forward<T>(default_st); // alternative
else return st;
}
template<typename T, typename F>
const T& get_or_default(const T& st, const T& default_st, F empty) {
if(empty(st)) return default_st;
else return st;
}
好吧,这里有一些东西。要直接表达您的要求,可以使用std::variant<std::string, std::string&>
之类的函数返回类型。尽管我还没有检查变体是否可以存储引用。或者来自第三方图书馆的类似资料。或者<>?您也可以编写自己的类包装字符串和字符串参考
(不是真正的代码(
struct StringOrRef {
enum class Type {Value, Ref} type;
union {
std::string value;
std::reference_wrapper<const std::string> ref;
};
...
};
检查主题:在C++中辨别并集。
但我认为你的例子还有更大的问题!请考虑数据的所有权。std::string获取所传递数据的所有权。这就是它复制数据的原因。因此,当函数返回时,被调用方确信它有一个数据,只要他持有该值,就不需要担心它。
如果您设计了一个函数来返回对传递的参数值的引用,则需要确保该值在与传递的参数(返回引用的参数(相同的寿命内使用
所以考虑一下:
StringOrRef func(strging const& a, string const& b);
...
StringOrRef val;
{ // begin scope:
SomeStruct s = get_defaul();
val = func("some value", s.get_ref_to_internal_string());
}// end of val scope
val; // is in scope but may be referencing freed data.
这里的问题是临时对象SomeStruct s
。如果它的成员函数get_ref_to_internal_string() -> string&
向该对象的字符串字段返回一个ref(这通常是它的实现方式(,那么当s
超出范围时,该ref将变为无效。也就是说,它引用的是释放的内存,这些内存可能已经被赋予了其他一些对象。如果您在val
中捕获该引用,那么val将引用无效数据。如果这一切都以access violation
或一个信号结束,你将是幸运的。最坏的情况是,你的程序会继续运行,但会随机崩溃。
- 当一个新对象被分配到它的地址时,对象是否必须被销毁
- C++ 如何在将新对象分配给另一个对象时创建新对象
- 重用对象与创建新对象
- C++,创建新对象时类的对象更改
- 运算符重载 += 添加新对象
- 如何在运行时在对象数组中动态追加新对象C++并打印它们
- 从使用概念定义的函数返回新对象
- 从 Rcpp 函数返回指向"新"对象的指针的正确方法
- 如何删除派生类中基类对象的新对象
- 有没有一种方法可以从函数中返回一个新对象或对现有对象的引用
- 为模板参数类型中的新对象分配内存
- 删除通过取消引用新对象初始化的对象
- C++ 实例化新对象时不接受继承方法默认参数值
- 有没有办法删除传递给函数"foo(新对象())"的对象?
- 将 Eigen::MatrixXd 转换为 arma::mat 并在新对象上制作副本
- 创建新对象并立即为其设置属性时出现编译器错误
- 如何异步销毁对象并立即分配一个新对象
- 删除传递给 C++ 中成员函数的新对象
- 具有构造函数的新对象数组,需要在C++中设置参数
- 我可以制作一个对象方法,如果单独调用,它将自行修改,但如果在复制初始化期间调用,则会返回一个新对象?