
1. The exception specifications are not clear - All predicates (exists, is_*) will throw on errors but you need to look into the status functions to see it. - What happens if an error occurs while iteratoring a directory or when the recursive iterator can't descend into a sub-folder. 2. Why not include the system_error code in the file_status object? If you want to avoid exceptions with the currenct code you need to write code like: system_error_code ec; file_status f(status(p, ec)); if (exists(f) && is_directory(f)) .. else if (status_known(f)) cout << "path is not a directory"; else cout << system_error_message(ec); // can't find this function in the TR2 and // I don't care what the problem is. system_error_code ec; if (is_regular(status(p, ec))) ... Which is kind of messy since the ec and f can't be scoped. It also seem strange that you need to define a system_error_code variable just to avoid exceptions. With a file_status object defined as struct file_status { explicit file_status(file_type v = status_unknown, system_error_code e = 0); file_type type() const; system_error_code error_code() const; std::string system_error_message() const; operator safe_bool() const { return ec == 0; } }; the code can be written as: if (file_status f(p, std::nothrow_t)) if (exists(f) && is_directory(f)) ... else cout << "Path is not a directory"; else cout << f.system_error_message(); and if (is_regular(status(p, std::nothrow_t))) ... 3. Why not differentiate storage type and interface type in the basic_path class?

"Martin Adrian" <adrianm@touchdown.se> wrote in message news:loom.20060310T081501-996@post.gmane.org...
1. The exception specifications are not clear - All predicates (exists, is_*) will throw on errors but you need to look into the status functions to see it.
Yes, the predicates do throw exceptions, and if you don't want that behavior, you would have to use the status functions. The thought is that it providing non-throwing versions of each of the status functions isn't worth the added convenience. I'm already worried about the size of the library.
- What happens if an error occurs while iteratoring a directory
There is a non-throwing constructor available, but currently operator++ does not have a non-throwing version.
or when the recursive iterator can't descend into a sub-folder.
That case is treated as an empty sub-folder.
2. Why not include the system_error code in the file_status object?
Turn the question around. Why would it be desirable to include a system_error code in the file status? I'm not seeing any real advantage - perhaps I'm missing something?
If you want to avoid exceptions with the currenct code you need to write code like:
system_error_code ec; file_status f(status(p, ec));
if (exists(f) && is_directory(f)) .. else if (status_known(f)) cout << "path is not a directory"; else cout << system_error_message(ec); // can't find this function in the TR2
and
// I don't care what the problem is. system_error_code ec; if (is_regular(status(p, ec))) ...
Which is kind of messy since the ec and f can't be scoped. It also seem strange that you need to define a system_error_code variable just to avoid exceptions.
With a file_status object defined as
struct file_status { explicit file_status(file_type v = status_unknown, system_error_code e = 0); file_type type() const; system_error_code error_code() const; std::string system_error_message() const; operator safe_bool() const { return ec == 0; } };
the code can be written as:
if (file_status f(p, std::nothrow_t)) if (exists(f) && is_directory(f)) ... else cout << "Path is not a directory"; else cout << f.system_error_message();
and
if (is_regular(status(p, std::nothrow_t)))
I assume you meant "std::nothrow" rather than "std::nothrow_t". If you provide "system_error_code nothrow;" somewhere, then you can already write that. All we are talking about is the spelling of "nothrow", it seems to me.
3. Why not differentiate storage type and interface type in the basic_path class?
Not sure what you mean. Could you give an example? Thanks, --Beman

Yes, the predicates do throw exceptions, and if you don't want that behavior, you would have to use the status functions. The thought is that it providing non-throwing versions of each of the status functions isn't worth the added convenience. I'm already worried about the size of the library.
I am not worried about the exceptions. What worries me is that it is not clear which functions will throw and when. When I first started to use the library a long time ago I got the impression that exceptions were rare and came from filesystem corruption and racing conditions. Over time I have learned that filesystem exceptions are common and happens all the time also for trivial operations like exists and directory iterations in a perfectly helthy environment. When reading the new documentation I still get the same impression. Exceptions are mentioned together with std::bad_alloc and "cannot successfully complete their operational specifications". Examples don't show exceptions or as in "simple_ls.cpp" only handle them in random places without explanations.
- What happens if an error occurs while iteratoring a directory
There is a non-throwing constructor available, but currently operator++ does not have a non-throwing version.
No problem, just say in the documentation that operator++ might throw. (unfortunatly it makes the non-throwing constructor kind of useless since you still need a try/catch)
or when the recursive iterator can't descend into a sub-folder.
That case is treated as an empty sub-folder.
OK
2. Why not include the system_error code in the file_status object?
Turn the question around. Why would it be desirable to include a system_error code in the file status? I'm not seeing any real advantage - perhaps I'm missing something?
You get both the status and the system error from the same function. Why not keep them together so you don't have to use two variables all the time. I get a feeling that you still think exceptions are rare and that is not common to write code to handle or avoid them.
If you provide "system_error_code nothrow;" somewhere, then you can already write that. All we are talking about is the spelling of "nothrow", it seems to me.
No, I'm trying to avoid extra variable declarations that I think make the code more difficult to understand. Using std::nothrow make the intention clear. Using a variable named nothrow will only add confusion.
3. Why not differentiate storage type and interface type in the basic_path class?
Not sure what you mean. Could you give an example?
The path need a storage type with some requirements (basic_string interface?). I don't see why the interface must use the same type. Lets say I want to store a path in shared memory and use a string with an shmem allocator. The effect is then that I can only use operations on the path with strings stored in the same memory area. In short: Let the constructor, assign and operators always work on basic_string types regardless of what the storage type is. something like template <class TratitsT, class AllocatorT> basic_path(basic_string<CharT, TraitsT AllocatorT>& str) : m_path(str.begin(), str.end()) { }
participants (2)
-
Beman Dawes
-
Martin Adrian