在std :: vector中查找Iterator [英] Find Iterator in a std::vector
问题描述
我遇到了问题,我正在尝试创建一个系统来读取和写入.ini文件,但我仍然坚持如何正确添加部分/键。我以为我可以将它们作为对象添加到std :: vector中,所以我写了下面的代码片段(我删除了无关的代码):
I'm having a problem, i'm trying to create a System to read and write .ini files, but i'm stuck at how to correctly add the sections/keys. I thought i could add them as objects to a std::vector, so i wrote the following snippet (i removed code that is irrelevant):
// .h
class Ini
{
public:
class IniSection
{
friend class Ini;
private:
IniSection(Ini *ini, std::string section);
~IniSection();
private:
Ini *pIni;
std::string sectionName;
};
vector<IniSection *>::iterator Ini::FindSection(std::string section);
IniSection *AddSection(std::string name);
private:
vector<IniSection *> Sections;
};
typedef Ini::IniSection IniSection;
// .cpp
IniSection::IniSection(Ini *ini, std::string section) : pIni(ini), sectionName(section)
{
}
vector<IniSection *>::iterator Ini::FindSection(std::string section)
{
IniSection tempSection(NULL, section);
return find(Sections.begin(), Sections.end(), tempSection); // ERROR
}
IniSection *Ini::AddSection(std::string name)
{
vector<IniSection *>::const_iterator iter = FindSection(name);
if (iter == Sections.end())
{
IniSection *newSection = new IniSection(this, name);
Sections.push_back(newSection);
return newSection;
}
else
return *iter;
}
如你所见,我用
//错误
// ERROR
这是因为当我尝试构建它时我收到此错误:
that's because when i try to build it, i get this error:
错误C2679二进制'==':找不到哪个运算符需要右边的
操作数输入'const Ini :: IniSection'(或者没有可接受的
转换)
Error C2679 binary '==' : no operator found which takes a right-hand operand of type 'const Ini::IniSection' (or there is no acceptable conversion)
它出现在算法库中。所以我想我尝试获取迭代器的方式是错误的,所以也许有人能够帮助我。我在互联网上找不到适合我的东西。提前致谢!
It occurs in the algorithm library. So i guess the way i try to get the iterator is wrong, so maybe someone is able to help me out. I couldn't find something on the Internet that suited me. Thanks in advance!
推荐答案
上述代码存在以下几个问题。根据建议,您需要为 IniSection
定义运算符==
,以便 std: :find
能够比较 Sections
向量中的条目。但是,还有另一个问题:你的 FindSection
有点无用,因为你无法测试迭代器是否返回 Sections :: end()$处的点数c $ c>因为
Sections
是私人会员。如果我建议,你需要添加类似 hasSection
的方法,它返回 bool
,并测试是否存在或缺少使用它的部分。我冒昧地修改代码来说明这一点,随意根据你的需要改变它。
There are several issues with the above code. As suggested, you need to define an operator ==
for IniSection
in order for std::find
to be able to compare the entries in your Sections
vector. However, there is another problem: your FindSection
is somewhat useless because you cannot test whether the iterator returned points at Sections::end()
because Sections
is a private member. If I may suggest, you need to add something like a hasSection
method which returns bool
, and test for the presence or absence of sections using that. I took the liberty of modifying the code to illustrate the point, feel free to change it as you see fit.
#ifndef MAIN_HPP
#define MAIN_HPP
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
class Ini
{
public:
class IniSection
{
friend class Ini;
Ini& pIni;
std::string sectionName;
public:
IniSection(Ini& ini, const std::string& section);
friend bool operator == (const IniSection& _this, const IniSection& _other)
{
return _this.sectionName == _other.sectionName;
}
};
std::vector<IniSection>::iterator FindSection(const std::string& section);
std::vector<IniSection>::iterator AddSection(const std::string& section);
bool hasSection(const std::string& section);
std::vector<std::string> sectionNames();
private:
std::vector<IniSection> Sections;
};
typedef Ini::IniSection IniSection;
#endif // MAIN_HPP
main .cpp
main.cpp
#include "main.hpp"
IniSection::IniSection(Ini& ini, const std::string& section)
:
pIni(ini),
sectionName(section)
{}
std::vector<IniSection>::iterator Ini::FindSection(const std::string& section)
{
IniSection tempSection(*this, section);
return std::find(Sections.begin(), Sections.end(), tempSection);
}
std::vector<IniSection>::iterator Ini::AddSection(const std::string& section)
{
std::vector<IniSection>::iterator iter = FindSection(section);
if (iter == Sections.end())
{
Sections.emplace_back(*this, section);
return Sections.end() - 1;
}
else
{
return iter;
}
}
bool Ini::hasSection(const std::string& section)
{
return FindSection(section) != Sections.end();
}
std::vector<std::string> Ini::sectionNames()
{
std::vector<std::string> names;
for (const auto& s : Sections)
{
names.push_back(s.sectionName);
}
return names;
}
int main()
{
Ini ini;
ini.AddSection("Section1");
ini.AddSection("Section2");
ini.AddSection("Section3");
if (ini.hasSection("Section1"))
{
std::cout << "Ini contains section 1!\n";
}
if (!ini.hasSection("Section4"))
{
std::cout << "Adding section 4...\n";
ini.AddSection("Section4");
}
std::cout << "Ini contains the following sections:\n";
for (const auto& s : ini.sectionNames())
{
std::cout << "\t" << s << "\n";
}
return 0;
}
打印:
Ini contains section 1!
Adding section 4...
Ini contains the following sections:
Section1
Section2
Section3
Section4
另外,正如评论中所建议的, std :: unordered_map
是一个很好的表演者适合这种情况。
Also, as suggested in the comments, std::unordered_map
is a great performer and quite suitable for such scenarios.
PS您可能已经注意到我用对象替换了原始指针。像 std :: vector
这样的STL容器在内部处理分配和释放,因此不需要使用原始指针。
P.S. You may have noticed that I replaced raw pointers with objects. STL containers like std::vector
handle the allocation and deallocation internally, so there is no need to use raw pointers.
编辑
我已经修改了pastebin中的代码,但是有些东西丢失了(我不知道什么类型 IniPath
是 - 可能是 std :: string
?)。还有很大的改进空间,例如,你可以在 getSection
中添加几行来自动添加一个部分(如果它不存在)必须先用 hasSection
检查是否存在。如前所述,使用 std :: unordered_map
可以大大受益,因为插入,删除和查找都是分摊的常量时间。使用 std :: vector
,查找和检索元素将是线性时间。我不清楚的另一件事是为什么你需要将一个引用(或原始代码中的指针)存储到父对象(例如 IniSection&
在<$ c里面$ C> IniKey )。据我所知,你没有使用这些。只要您不存储原始指针,您也不需要实现自己的析构函数。
I have modified the code from pastebin, but there are some things missing (I'm not sure what type IniPath
is - maybe a std::string
?). There is a lot of room for improvement, for example, you can add a couple of lines to getSection
to add a section automatically if it doesn't exist (so you don't have to check for existence with hasSection
first). As mentioned before, you could greatly benefit from using std::unordered_map
as insertion, deletion and lookup are all amortised constant time. With std::vector
, finding and retrieving an element would be linear time. Another thing I am not clear about is why you need to store a reference (or a pointer in your original code) to the parent object (such as IniSection&
inside IniKey
). As far as I can tell, you are not using these. You also don't need to implement your own destructors as long as you are not storing raw pointers.
免责声明:我没有编译和测试此代码。
Disclaimer: I have not compiled and tested this code.
PS您可能希望在CodeReview上发布此内容以进一步改进。
P.S. You might want to post this on CodeReview for further improvements.
main.hpp
#include <vector>
#include <string>
#include <fstream>
#include <algorithm>
class Ini
{
public:
Ini();
~Ini();
bool Load(std::string path);
void Load(std::istream& input);
bool Save(std::string path);
void Save(std::ostream& output);
void Create(std::string path);
class IniSection
{
friend class Ini;
Ini& pIni;
std::string sectionName;
public:
IniSection(Ini& ini, const std::string& section);
~IniSection();
friend bool operator == (const IniSection& _this, const IniSection& _other)
{
return _this.sectionName == _other.sectionName;
}
std::string GetSectionName();
class IniKey
{
friend class IniSection;
IniSection& pSection;
std::string keyName;
std::string keyValue;
std::string commentValue;
public:
IniKey(IniSection& section, const std::string& key);
~IniKey();
friend bool operator == (const IniKey& _this, const IniKey& _other)
{
return _this.keyName == _other.keyName;
}
void SetValue(std::string value);
std::string GetValue();
std::string GetKeyName();
void AddComment(std::string comment);
std::string GetComment();
};
void RemoveAllKeys();
std::vector<IniKey>::iterator FindKey(const std::string& key);
std::vector<IniKey>::iterator AddKey(const std::string& key);
std::vector<IniKey>::iterator GetKey(const std::string& key);
bool hasKey(const std::string& key);
std::string GetKeyValue(const std::string& key);
void SetKeyValue(const std::string& key, const std::string& value);
private:
std::vector<IniKey> Keys;
};
void RemoveAllSections();
std::vector<IniSection>::iterator FindSection(const std::string& section);
std::vector<IniSection>::iterator AddSection(const std::string& section);
std::vector<IniSection>::iterator GetSection(const std::string& section);
bool hasSection(const std::string& section);
std::string GetKeyValue(std::string section, std::string key);
void SetKeyValue(std::string section, std::string key, std::string value);
private:
std::vector<IniSection> Sections;
};
typedef Ini::IniSection IniSection;
typedef IniSection::IniKey IniKey;
main.cpp
#include "main.hpp"
bool Ini::Load(std::string path)
{
std::ifstream input;
input.open(path.c_str(), std::ios::binary);
if (!input.is_open())
return false;
Load(input);
input.close();
return true;
}
void Ini::Load(std::istream& input)
{
std::vector<IniSection>::iterator section;
std::string lineValue;
enum
{
KEY,
SECTION,
COMMENT,
OTHER
};
while (getline(input, lineValue))
{
// TrimLeft(lineValue);
// TrimRight(lineValue, "\n\r");
if (!lineValue.empty())
{
unsigned int type = OTHER;
type = (lineValue.find_first_of("[") == 0 && (lineValue[lineValue.find_last_not_of(" \t\r\n")] == ']')) ? SECTION : OTHER;
type = ((type == OTHER) && (lineValue.find_first_of("=") != std::string::npos && lineValue.find_first_of("=") > 0)) ? KEY : type;
type = ((type == OTHER) && (lineValue.find_first_of("#") == 0)) ? COMMENT : type;
switch (type)
{
case SECTION:
section = AddSection(lineValue.substr(1, lineValue.size() - 2));
break;
case KEY:
{
size_t equalSpot = lineValue.find_first_of("=");
std::string keyName = lineValue.substr(0, equalSpot);
std::string keyValue = lineValue.substr(equalSpot + 1);
std::vector<IniKey>::iterator key = section->AddKey(keyName);
key->SetValue(keyValue);
break;
}
default:
break;
}
}
}
}
void Ini::Create(std::string path)
{
std::fstream file;
file.open(path, std::fstream::out);
file.close();
}
bool Ini::Save(std::string path)
{
std::ofstream output;
output.open(path.c_str(), std::ios::binary);
if (!output.is_open())
{
output.close();
return false;
}
Save(output);
output.close();
return true;
}
void Ini::Save(std::ostream& output)
{
std::string section;
std::vector<IniSection>::iterator iter1;
for (iter1 = Sections.begin(); iter1 != Sections.end(); iter1++)
{
section = "[" + iter1->GetSectionName() + "]";
output << section << "\r\n";
std::vector<IniKey>::iterator iter2;
for (iter2 = iter1->Keys.begin(); iter2 != iter1->Keys.end(); iter2++)
{
std::string comment = "# " + iter2->GetComment();
if (comment != "# ")
output << comment << "\r\n";
std::string key = iter2->GetKeyName() + "=" + iter2->GetValue();
output << key << "\r\n";
}
output << "\r\n";
}
}
std::string Ini::GetKeyValue(std::string section, std::string key)
{
if (hasSection(section))
{
auto s = GetSection(section);
if (s->hasKey(key))
{
return s->GetKey(key)->GetValue();
}
}
return std::string();
}
void Ini::SetKeyValue(std::string section, std::string key, std::string value)
{
if (hasSection(section))
{
auto s = GetSection(section);
if (s->hasKey(key))
{
s->GetKey(key)->SetValue(value);
}
}
}
// IniSection -----------------------------------------------------------------------------------
IniSection::IniSection(Ini& ini, const std::string& section) : pIni(ini), sectionName(section)
{
}
void Ini::RemoveAllSections()
{
// std::vector<IniSection *>::iterator iter;
// for (iter = Sections.begin(); iter != Sections.end(); iter++)
// delete *iter;
Sections.clear();
}
std::vector<IniSection>::iterator Ini::FindSection(const std::string& section)
{
IniSection tempSection(*this, section);
return std::find(Sections.begin(), Sections.end(), tempSection);
}
std::vector<IniSection>::iterator Ini::AddSection(const std::string& section)
{
std::vector<IniSection>::iterator iter = FindSection(section);
if (iter == Sections.end())
{
Sections.emplace_back(*this, section);
return Sections.end() - 1;
}
else
return iter;
}
std::vector<IniSection>::iterator Ini::GetSection(const std::string& section)
{
return FindSection(section);
}
std::string IniSection::GetSectionName()
{
return sectionName;
}
std::string IniSection::GetKeyValue(const std::string& key)
{
if (hasKey(key))
{
return GetKey(key)->GetValue();
}
return std::string();
}
void IniSection::SetKeyValue(const std::string& key, const std::string& value)
{
if (hasKey(key))
GetKey(key)->SetValue(value);
}
// IniKey -----------------------------------------------------------------------------------
void IniSection::RemoveAllKeys()
{
// std::vector<IniKey *>::iterator iter;
// for (iter = Keys.begin(); iter != Keys.end(); iter++)
// delete *iter;
// std::vector manages the allocations automatically
// as long as you are not using raw pointers
Keys.clear();
}
std::vector<IniKey>::iterator IniSection::FindKey(const std::string& key)
{
IniKey tempKey(*this, key);
return std::find(Keys.begin(), Keys.end(), tempKey);
}
std::vector<IniKey>::iterator IniSection::AddKey(const std::string& key)
{
if (hasKey(key))
{
return GetKey(key);
}
else
return Keys.insert(Keys.end(), {*this, key});
}
bool IniSection::hasKey(const std::string& key)
{
return FindKey(key) != Keys.end();
}
void IniKey::SetValue(std::string value)
{
keyValue = value;
}
std::string IniKey::GetValue()
{
return keyValue;
}
std::string IniKey::GetKeyName()
{
return keyName;
}
std::vector<IniKey>::iterator IniSection::GetKey(const std::string& key)
{
if (hasKey(key))
return GetKey(key);
return Keys.end();
}
bool Ini::hasSection(const std::string& section)
{
return FindSection(section) != Sections.end();
}
void IniKey::AddComment(std::string comment)
{
commentValue = comment;
}
std::string IniKey::GetComment()
{
return commentValue;
}
int main()
{
// How i want to use it:
// Write:
Ini ini;
ini.Create(IniPath);
ini.Load(IniPath);
// Check if "Test" section exists and add it if it doesn't
if (!ini.hasSection("Test"))
{
ini.AddSection("Test");
}
auto secTest(ini.GetSection("Test"));
secTest->AddKey("Key1")->SetValue("KeyValue1");
secTest->GetKey("Key1")->AddComment("This is a Test");
ini.Save(IniPath);
// Read:
Ini ini1;
ini1.Load(IniPath);
// IniSection *Section = ini.GetSection("Test");
if (ini1.hasSection("Test"))
{
if (ini1.GetSection("Test")->hasKey("Key1"))
{
std::string keyValue = ini.GetSection("Test")->GetKeyValue("Key1");
}
}
return 0;
}
这篇关于在std :: vector中查找Iterator的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!