Saturday, November 5, 2022

[FIXED] How can I retrieve the return value of pclose when the unique_ptr is destroyed?

Issue

As @user17732522 pointed out that the deleter of std::unique_ptr is supposed to be callable with exactly one pointer as argument.

How can I retrieve the return value of pclose when the unique_ptr is destroyed?

This code snippet does not compile,

#include<memory>
#include<iostream>
#include<string>
#include<cstdio>

int ExecCmd(const std::string& cmd, std::string& output)
{
    int ret = 0;

    {
        std::unique_ptr<FILE, void(*)(FILE*, int*)> pipe(popen(cmd.c_str(), "r"), [](FILE* file, int* ret_ptr){
                              if(NULL==file)
                              {
                                  *ret_ptr = -1;
                              } 
                              else 
                              {
                                  *ret_ptr = pclose(file);
                              }
                         });
    }

    return ret;
}

int main()
{

}

Whereas this code snippet below compiles.

#include<memory>
#include<iostream>
#include<string>
#include<cstdio>

int ExecCmd(const std::string& cmd, std::string& output)
{
    int ret = 0;

    {
        std::unique_ptr<FILE, void(*)(FILE*)> pipe(popen(cmd.c_str(), "r"), [](FILE* file){
                              if(NULL==file)
                              {
                                 
                              } 
                              else 
                              {
                                    pclose(file);
                              }
                         });
    }

    return ret;
}

int main()
{

}

Here is what the compiler complains about the former code snippet:

In file included from /opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/memory:76,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/bits/unique_ptr.h: In instantiation of 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = _IO_FILE; _Dp = void (*)(_IO_FILE*, int*)]':
<source>:20:27:   required from here
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/bits/unique_ptr.h:357:63: error: static assertion failed: unique_ptr's deleter must be invocable with a pointer
  357 |         static_assert(__is_invocable<deleter_type&, pointer>::value,
      |                                                               ^~~~~
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/bits/unique_ptr.h:357:63: note: 'std::integral_constant<bool, false>::value' evaluates to false
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/bits/unique_ptr.h:361:24: error: too few arguments to function
  361 |           get_deleter()(std::move(__ptr));
      |           ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~

I tried this code snippet to acquire the return value, but it does not compile:

#include<memory>
#include<iostream>
#include<string>
#include<cstdio>

int ExecCmd(const std::string& cmd, std::string& output)
{
    int ret = 0;

    {
        std::unique_ptr<FILE, void(*)(FILE*)> pipe(popen(cmd.c_str(), "r"), [&ret](FILE* file){
                              if(NULL==file)
                              {
                                  ret = -1;
                              } 
                              else 
                              {
                                  ret = pclose(file);
                              }
                         });
    }

    return ret;
}

int main()
{

}

Could anybody shed some light on this matter?


Solution

Since you can only provide a custom deleter which can be callable with exactly one pointer as argument, you can not have the lambda with two arguments in it as deleter.

Your lambda with capture will also not work, as it can not be converted to a pointer to a function (i.e. only stateless lambdas can be converted to free function pointers type)


How can I retrieve the return value of pclose when the std::unique_ptr is destroyed?

Using lambda

int ExecCmd(const std::string& cmd, std::string& output)
{
    int ret = 0;
    const auto deleter = [&ret](FILE* file) { ret = file ? pclose(file) : 0; };
    {
        std::unique_ptr<FILE, decltype(deleter)> pipe(popen(cmd.c_str(), "r"), deleter);
    }
    return ret;
}

See a demo



Answered By - JeJo
Answer Checked By - Robin (PHPFixing Admin)

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.