cppfront
cppfront copied to clipboard
Caveat: There's little else in the C stdlib that allocates a resource
@hsutter regarding your question: https://github.com/hsutter/cppfront/blob/bf5998a5e9145f11a935c2700b1db50f6e2de2fa/include/cpp2util.h#L809
I am currently trying to use cppfront to build my project (that's why I send PRs - I am implementing what I am missing).
I use something like your c_raii
(I call it scope_exit
and I have a function on_scope_exit
that produces it) for handling popen
(here I am using UFCS chaining from here: https://github.com/hsutter/cppfront/pull/18):
execute: (cmd : std::string) -> auto = {
std_out := popen(cmd.c_str(), "r").on_scope_exit(pclose);
buf : std::array<char, 1024> = ();
output : std::string = ();
read_size := fread(buf.begin(), 1, buf.size(), std_out);
while read_size > 0 next read_size = fread(buf.begin(), 1, buf.size(), std_out) {
output += std::string(buf.begin(), read_size);
}
return output;
}
and to remove temporary directories on scope exit
create_temporary_directory: () -> auto = {
tmp := fs::temp_directory_path();
build_dir := on_scope_exit(tmp / "md_tests/build", :(p : fs::path) = {
fs::remove_all(p);
std::cout << "removed tmp directory: (p)$" << std::endl;
} );
fs::create_directories(build_dir);
std::cout << "created tmp directory: (fs::path(build_dir))$" << std::endl;
return build_dir;
}
My current implementation of on_scope_exit()
:
template <typename T, typename D>
struct scope_exit {
scope_exit(T v, D d)
: value(v)
, deleter(d)
{
}
~scope_exit() {
deleter(value);
}
operator T&() { return value; }
private:
T value;
D deleter;
};
on_scope_exit: (forward v : _, forward d : _) -> auto = {
return scope_exit(v,d);
}
I will check your implementation and will let you know.
Thanks, let me know what you find!
I checked your implementation. I don't understand why you are using (D)(x);
in the lambda for the destructor but it seems to work with C functions.
auto good = c_raii(std::fopen("dd", "w"), std::close); // works
but this doesn't:
auto bad = c_raii(std::fopen("dd", "w"), [](FILE* x) { std::fclose(x); } ); // doesn't work
The above is useful when additional actions are needed or for logging purposes.
I know that you care about real cases so I check other C functions from POSIX that might shed some light on potential use cases.
I found functions for handling POSIX shared memory objects:
int shm_open(const char *name, int oflag, mode_t mode);
int shm_unlink(const char *name);
This is an interesting case as the return type is a file descriptor that is used for the next actions (so T
will be int
) but unlinking needs to be done on the name
argument. That makes cpp2::c_raii
useless for that case as it would need to use e.g. lambda with a capture list that will not match the function pointer.
Is there a reason why the c_raii
doesn't look like the code below?
template<typename T, typename D>
class c_raii {
T t;
D dtor;
public:
c_raii( T t_, D d_) // maybe forwarding the arguments would be better
: t{ t_ }
, dtor{ d_ }
{ }
~c_raii() { dtor(t); }
operator T&() { return t; }
//...
};
Good idea, thanks! Applied.