Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

By not existing keys returns 0 #32

Open
SerTetora opened this issue Jun 13, 2023 · 4 comments
Open

By not existing keys returns 0 #32

SerTetora opened this issue Jun 13, 2023 · 4 comments

Comments

@SerTetora
Copy link

Hi, @Rookfighter. thank you for a great tool.

I'm trying to read an example.ini. And if the group-key-pair not exist in the ini-file, it returns "" that by converting to int gives 0 and by converting to bool gives false. It is in my opinion an unexpected behavior.

example.ini

[Group_1]
key_1 = 1;

main.cpp

#include <iostream>
#include "inicpp.h"
int main() {
	 ini::IniFile inifile;
	 inifile.load("example.ini");

	 int val_1 = inifile["Group_1"]["key_1"].as<int>();
	 int val_2 = inifile["Group_1"]["key_2"].as<int>();
	 
	 std::cout << "value 1 = " << val_1 << std::endl;
	 std::cout << "value 2 = " << val_2 << std::endl;
	 return 0;
}

Output:

value 1 = 1
value 2 = 0

My workaround for now is

#include <iostream>
#include <stdexcept>
#include "inicpp.h"

int readInt(ini::IniFile &inifile, const std::string &group, const std::string &key) {
	if (inifile[group][key].as<std::string>() == "")
		throw std::runtime_error(key + " is not found in " + group + "\n");
	else
		return inifile[group][key].as<int>();
}

int main() {
	ini::IniFile inifile;
	inifile.load("example.ini");

	try
	{
		int val_1 = readInt(inifile, "Group_1", "key_1");
		std::cout << "value 1 = " << val_1 << std::endl;
	} catch (...)
	{
		std::cout << "key_1 is not found in Group_1" << std::endl;
		inifile.clear();
		return 1;
	}

	try
	{
		int val_2 = readInt(inifile, "Group_1", "key_2");
		std::cout << "value 2 = " << val_2 << std::endl;
	} catch (...)
	{
		std::cout << "key_2 is not found in Group_1" << std::endl;
		inifile.clear();
		return 1;
	}

	return 0;
}
@SerTetora
Copy link
Author

And one more additional question to using of ini::IniFile. Should I always do a inifile.clear() or inifile will be automatically destructed when it is not used anymore?

@Rookfighter
Copy link
Owner

Hi @SerTetora,

thanks for using inifile-cpp and thanks for your elaborate explanation!

So if I understand you correctly either the section or the key of a section that you try to access does not exist in the inifile, correct?

It makes sense that a non-existing value actually returns "". The IniFile class and the IniSection class are both derived from std::map. That means, whenever you use operator[] (or any other std::mapmethod) you actually use a std::map method. From cppreference I get that if a key does not exist and is accessed using òperator[]the key gets insterted and the value (herestd::string`) gets default constructed.

If you want to check if a section or key exists you can use std::map's find method (or contains if you use c++20).

I agree that the behaviour when converting to a int or bool is unexpected. What would your expected behaviour be? Throwing an exception? An assertion (for safe debug and fast release builds)?

@Rookfighter
Copy link
Owner

And one more additional question to using of ini::IniFile. Should I always do a inifile.clear() or inifile will be automatically destructed when it is not used anymore?

Actually IniFile is derived from std::map so it behaves the same. If it goes out of scope it clears all its resources, so no need to call clear(). Also note that clear() actually does not release any memory or resources:

Invalidates any references, pointers, or iterators referring to contained elements. Any past-the-end iterator remains valid.

Since any past iterator remains valid, I guess the memory might not be cleared (from clear)

@SerTetora
Copy link
Author

So if I understand you correctly either the section or the key of a section that you try to access does not exist in the inifile, correct?

Correct.

It makes sense that a non-existing value actually returns "". The IniFile class and the IniSection class are both derived from std::map. That means, whenever you use operator[] (or any other std::mapmethod) you actually use a std::map method. From cppreference I get that if a key does not exist and is accessed using operator[] the key gets inserted and the value (herestd::string) gets default constructed.

If you want to check if a section or key exists you can use std::map's find method (or contains if you use c++20).

Thank you for the clarification and suggestion. With find it would be a more clear way to check the key existence.

I agree that the behaviour when converting to a int or bool is unexpected. What would your expected behaviour be? Throwing an exception? An assertion (for safe debug and fast release builds)?

In my application, there are cases in runtime when values in inifile.ini are invalid. In those cases, I will use default values. So will prefer throwing an exception that I can catch.

Actually IniFile is derived from std::map so it behaves the same. If it goes out of scope it clears all its resources, so no need to call clear(). Also note that clear() actually does not release any memory or resources:

I really appreciate your explanation. It helped me a lot!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants