directory_entry
multithreading concernsSection: 12 [filesys.ts::class.directory_entry] Status: TS Submitter: Stephan T. Lavavej Opened: 2014-02-03 Last modified: 2017-07-30
Priority: Not Prioritized
View all other issues in [filesys.ts::class.directory_entry].
View all issues with TS status.
Discussion:
Addresses: filesys.ts
12 [class.directory_entry] depicts directory_entry
as having mutable m_status
and
m_symlink_status
data members. This is problematic because of C++11's multithreading
guarantees, which say that const
member functions are simultaneously callable.
As a result, mutable
data members must be protected with synchronization, which was
probably not considered during this design. The complexity and expense may be acceptable
in directory_entry
(since it can save filesystem queries, apparently) but it would be
very very nice to have a note about this.
[2014-02-13 LWG/SG-3 discussed in Issaquah: Beman and STL will work together to better understand the concerns, and to formulate a solution. This is not a blocking issue for finishing the TS, but is a blocking issue for merging into the IS]
[2014-04-17 Beman provides proposed wording]
[2014-06-19 Rapperswil LWG decides to remove mutable private members. Beman provides wording.]
Proposed resolution:
Change 12 [class.directory_entry] as indicated:namespace std { namespace experimental { namespace filesystem { inline namespace v1 { class directory_entry { public: // constructors and destructor directory_entry() = default; directory_entry(const directory_entry&) = default; directory_entry(directory_entry&&) noexcept = default; explicit directory_entry(const path& p);explicit directory_entry(const path& p, file_status st=file_status(),file_status symlink_st=file_status());~directory_entry(); // modifiers directory_entry& operator=(const directory_entry&) = default; directory_entry& operator=(directory_entry&&) noexcept = default; void assign(const path& p);void assign(const path& p, file_status st=file_status(),file_status symlink_st=file_status()); void replace_filename(const path& p);void replace_filename(const path& p, file_status st=file_status(),file_status symlink_st=file_status()); // observers const path& path() const noexcept; file_status status() const; file_status status(error_code& ec) const noexcept; file_status symlink_status() const; file_status symlink_status(error_code& ec) const noexcept; bool operator< (const directory_entry& rhs) const noexcept; bool operator==(const directory_entry& rhs) const noexcept; bool operator!=(const directory_entry& rhs) const noexcept; bool operator<=(const directory_entry& rhs) const noexcept; bool operator> (const directory_entry& rhs) const noexcept; bool operator>=(const directory_entry& rhs) const noexcept; private: path m_path; // for exposition onlymutable file_status m_status; // for exposition only; stat()-likemutable file_status m_symlink_status; // for exposition only; lstat()-like}; } } } } // namespaces std::experimental::filesystem::v1
A directory_entry
object stores a path
object,
a .
file_status
object for non-symbolic link status, and a file_status
object for symbolic link status
The
file_status
objects act as value caches.
[Note: Becausestatus()
on a pathname may be a relatively expensive operation, some operating systems provide status information as a byproduct of directory iteration. Caching such status information can result in significant time savings. Cached and non-cached results may differ in the presence of file system races. —end note]
directory_entry
constructors
[directory_entry.cons]
Add the description of this constructor in its entirety:
explicit directory_entry(const path& p);
Effects: Constructs an object of typedirectory_entry
Postcondition:
path() == p
.
explicit directory_entry(const path& p, file_status st=file_status(),file_status symlink_st=file_status());
Strike the description
directory_entry
modifiers
[directory_entry.mods]
Add the description of this function in its entirety:
void assign(const path& p);
Postcondition:
path() == p
.
void assign(const path& p, file_status st=file_status(),file_status symlink_st=file_status());
Strike the description
Add the description of this function in its entirety:
void replace_filename(const path& p);
Postcondition:
path() == x.parent_path() / p
wherex
is the value ofpath()
before the function is called.
void replace_filename(const path& p, file_status st=file_status(),file_status symlink_st=file_status());
Strike the description
directory_entry
observers
[directory_entry.obs]
const path& path() const noexcept;
Returns:
m_path
file_status status() const; file_status status(error_code& ec) const noexcept;
Effects: As if,if (!status_known(m_status)) { if (status_known(m_symlink_status) && !is_symlink(m_symlink_status)) { m_status = m_symlink_status; } else { m_status = status(m_path[, ec]); } }Returns:
.
m_statusstatus(path()[, ec])Throws: As specified in Error reporting (7).
file_status symlink_status() const; file_status symlink_status(error_code& ec) const noexcept;
Effects: As if,if (!status_known(m_symlink_status)) { m_symlink_status = symlink_status(m_path[, ec]); }Returns:
.
m_symlink_statussymlink_status(path()[, ec])Throws: As specified in Error reporting (7).
bool operator==(const directory_entry& rhs) const noexcept;
Returns:
m_path == rhs.m_path
.
[Note: Status members do not participate in determining equality. — end note]
bool operator!=(const directory_entry& rhs) const noexcept;
Returns:
m_path != rhs.m_path
.
bool operator< (const directory_entry& rhs) const noexcept;
Returns:
m_path < rhs.m_path
.
bool operator<=(const directory_entry& rhs) const noexcept;
Returns:
m_path <= rhs.m_path
.
bool operator> (const directory_entry& rhs) const noexcept;
Returns:
m_path > rhs.m_path
.
bool operator>=(const directory_entry& rhs) const noexcept;
Returns:
m_path >= rhs.m_path
.