C++ 将Get()拆分为容器的Has()和Get()有什么好处吗?
假设我有一个C++ 将Get()拆分为容器的Has()和Get()有什么好处吗?,c++,search,stl,containers,C++,Search,Stl,Containers,假设我有一个向量,和一个GetMyClass(),比如: std::vector<MyClass> mcs; // assume mcs has some elements... MyClass* GetMyClass() { auto it = std::find_if(mcs.begin(), mcs.end(), [](const MyClass& mc) { return mc.condition() == true;
向量
,和一个GetMyClass()
,比如:
std::vector<MyClass> mcs; // assume mcs has some elements...
MyClass* GetMyClass()
{
auto it = std::find_if(mcs.begin(), mcs.end(),
[](const MyClass& mc)
{
return mc.condition() == true;
});
if (it == mcs.end())
return nullptr;
else
return &(*it);
}
如果用户想知道是否存在MyClass
,则调用HasMyClass()
;
如果用户想要获得一个MyClass
,并且非常确定必须有一个,那么他直接调用GetMyClass()
。如果用户想要一个MyClass
,但不确定,那么他会同时调用这两个类
为了消除代码重复并避免重复执行,我将其修改为:
std::vector<MyClass> mcs; // assume mcs has some elements...
// std::vector<MyClass>::iterator temp; // originally this
MyClass* temp = nullptr; // changed to this according to Hsi-Hung Shih's advice
bool HasMyClass()
{
auto it = std::find_if(mcs.begin(), mcs.end(),
[](const MyClass& mc)
{
return mc.condition() == true;
});
if (it == mcs.end())
{
temp = nullptr;
return false;
}
else
{
temp = &(*it);
return true;
}
}
MyClass& GetMyClass()
{
if (temp == nullptr)
{
HasMyClass();
}
MyClass& mc = (*temp);
temp = nullptr;
return mc;
}
std::vector mcs;//假设mcs有一些元素。。。
//std::vector::迭代器温度;//原来这个
MyClass*temp=nullptr;//按照西鸿禧的建议改成了这样
boolhasmyclass()
{
auto it=std::find_if(mcs.begin(),mcs.end(),
[](常数MyClass和mc)
{
返回mc.condition()==true;
});
if(it==mcs.end())
{
温度=零PTR;
返回false;
}
其他的
{
温度=&(*it);
返回true;
}
}
MyClass&GetMyClass()
{
if(temp==nullptr)
{
HasMyClass();
}
MyClass&mc=(*温度);
温度=零PTR;
返回mc;
}
我的问题是:
增加一个Has()
函数有什么好处吗?
如果是这样,这会减轻用户的负担吗?这会使代码使用的意图更加明确吗?额外的复杂性值得吗?
谢谢 我建议保留
GetMyClass
的原始实现。我将添加HasMyClass
,作为一个方便的函数,用于那些只需要这些信息的情况。
您可以使用GetMyClass
实现HasMyClass
。这是一个微不足道的实现
bool HasMyClass()
{
return (GetMyClass() != nullptr);
}
如果函数使用
if ( HasMyClass() )
{
MyClass* c = GetMyClass();
}
将进行两次搜索。这是对函数的错误使用,但您无法阻止它们
更好地使用HasMyClass的方法是:
if ( HasMyClass() )
{
// Follow path 1 (does not involve call to GetMyClass)
}
else
{
// Follow path 2 (does not involve call to GetMyClass either)
}
而且很确定一定有一个
已经给出了答案:如果你不能确定,你不能不检查就处理返回值
但是这种编程看起来像是一个旧的posix接口,必须检查每个retval。从C++中,你可以从STL中获得更多的功能,而不用编写这样的代码。我建议您查看一下
或者干脆全部:
我相信你可以用stl功能做很多事情。编写自己的搜索函数、访问它们、检查检索以及使用值/迭代器执行某些操作通常不能通过手工编写的代码来完成
第二次尝试可能是抛出异常,如throw NotFound_t()代码>通常的实现是更改接口以将指针作为参数传递,并返回是否找到对象:
bool TryGetMyClass(MyClass* ptr)
{
auto it = std::find_if(mcs.begin(), mcs.end(),
[](const MyClass& mc)
{
return mc.condition() == true;
});
if (it == mcs.end())
{
ptr = nullptr;
return false;
}
else
{
ptr = &(*it);
return true;
}
}
用法示例:
if(TryGetMyClass(ptr))
... // Ok, ptr not null
else
... // Handle null pointer
检查返回值是否存在潜在故障是常见的API设计,因此程序员应该熟悉它,并且可以轻松地使用它。如果他们忘记检查它,他们将知道何时取消引用它
当找不到异常时,可以抛出异常,但在容器中找不到异常通常不是异常,最好不要抛出异常
顺便说一下,您的代码也很危险,因为迭代器“temp”在您之前的查找之后可能无效。它可能是从向量中删除项的结果。副作用不明的功能非常差
总之,让人们熟悉您的API。不要为了使代码看起来可爱而使代码复杂化,比如允许人们不检查返回值是否存在潜在故障
编辑
如果您的数据可以是nullptr,那么您可以定义一个要返回的数据类,在该类中它可以指示故障状态。如果您很懒,可以使用std::pair来完成这项工作
struct Data {
bool is_failed;
MyClass* data;
};
老实说,这些函数表明,包装STL方法并没有实现任何功能。那些已经有一个成熟的模式来沟通“没有发现”,C++程序员已经熟悉了。你的方法连你自己都弄糊涂了
相反,您应该做的是在std::find
中提供合适的谓词 返回MyClass.condition()==true代码>??你的意思是返回mc.condition()==true代码>如果用户不确定并同时调用这两个,则搜索将执行两次,而之前只执行一次。此外,您首先假定用户不确定,但无法检查nullptr
的返回值。为什么您相信同一个用户不会不调用Has()
?您在if(temp==mcs.end()return&(*it);
局部变量的返回地址UB
@billz:False.&(*it)中遗漏了一些括号
是向量中某个元素的地址。您考虑的是&it
。但是通常HasMyClass()
会导致GetMyClass()
,这就是为什么我试图借助temp
迭代器避免这两次搜索,以便可以调用if(!HasMyClass())return;MyClass*c=GetMyClass();c->剂量测定法();
无需进行两次搜索。@MarsonMao,你可以这样做。但是,将迭代器作为全局变量存储在函数外部不是一个好的设计决策。是的,我知道,实际上向量和迭代器以及这些方法将被包装在一个类中;向量和迭代器将是私有成员。我将它们作为全局成员,只是为了含蓄性。@MarsonMao,那就没那么糟糕了。是的,检查retval非常烦人。但是我不太明白为什么我应该对每个
使用。在这种情况下,你能给我一些提示吗?你是对的,我应该对临时
使用MyClass*
,而不是迭代器。但我试图实现的是为了用户,我认为在很多情况下检查返回值是烦人和多余的
struct Data {
bool is_failed;
MyClass* data;
};