我正在编写一个函数,该函数应接受const std::string &
,但也应接受一个特殊的nullptr
值。目前,我正在使用const std::string *
。但是,我觉得应该有更多的C ++方式来执行此任务。
我最强的对点是按值传递(字符串不会很长,但是我不想复制64kB)。这也意味着我不希望像optional<T>
这样的对象具有T
类型的值字段。另外,我不想使用任何外部库。我的项目没有使用Boost或GSL,而只是使用纯C ++(确切地说是C ++ 17)。
是否存在标准的库类(奇迹发生在namespace std
中)或这种情况的广泛接受的习惯用法?
答案 0 :(得分:6)
如果std::optional
支持引用,那将是一种很好的“现代”方式。
但是:
古老,久经考验且清晰易读的解决方案是使用指针。这种方法绝对可以完成您需要做的所有事情。
只需这样做,然后继续将您的宝贵时间花在更重要的事情上!
答案 1 :(得分:3)
这个问题的一个有趣方面是,我更普遍地看到了相反的观点:指定不允许为空的指针的C ++方法是什么?答案归结为相同的原则。
指针与引用之间的主要区别是:
如果使指针恒定,则第一个差异消失。 C ++具有“空引用”的方法是具有常量指针。请注意,我所说的是指针是常量,如T * const
,它独立于指向对象的常量是常量,如T const *
或const T *
。
您可能已经被训练为认为所有指针都是邪恶的,但这过于笼统了。原始指针是引用可选对象的一种好方法,这些对象是您不负责负责的。如果您负责释放内存,请使用智能指针,但如果其他人为您持有该内存,请使用引用或指针。如果需要该对象,请使用引用(不能为null);否则为null。一个指针,如果它是可选的(可以为null)。哦,这是假设您不需要更改所指向的对象,在这种情况下,不再需要引用。
话虽如此,在特定情况下可能会有其他选择。如果在空值和非空值之间没有共享代码,则最好使用重载函数,例如void foo(const std::string &)
和void foo()
。必须权衡各种折衷,包括API一致性。选择最适合您的情况的
答案 2 :(得分:1)
另一种方法是提供一个空字符串,您的函数可以通过对象身份检查来检测该空字符串:
#include <string>
namespace MyLibrary
{
static const std::string NULL_STRING;
void foo(const std::string& str)
{
if (&str == &NULL_STRING)
// ...
else
// ...
}
}
int main()
{
MyLibrary::foo("Hello, world!");
MyLibrary::foo("");
MyLibrary::foo(MyLibrary::NULL_STRING);
}
但是,有人可能会认为这有点浪费空间,我认为它不是特别习惯。但是,有时候,我在私有库代码中也采用了类似的方法(特别是与默认参数结合使用)。
答案 3 :(得分:1)
正如您特别要求的一些STD库奇迹:STD库实际上具有reference_wrapper
,可以与optional
结合使用,以某种方式实现您的要求:
template <class T>
using optional_ref = std::optional<std::reference_wrapper<T>>;
实际上很简单,但是访问起来也很麻烦:
void foo(optional_ref<std::string> str)
{
if (str)
printf("%s", str->get().c_str());
}
在呼叫站点上,它的工作效果非常好:
std::string str;
foo(str); // passes a reference
foo({}); // passes nothing
话虽如此,我也不认为使用;)(请参见已接受的答案)是个好主意。
答案 4 :(得分:-1)
编写两个函数:
void f(const string *s)
{
if (s)
{
// Use s
}
else
{
// Don't use s
}
}
void f(const string &s)
{
f(&s);
}