smart pointer to manage socket file descriptor

三世轮回 提交于 2021-02-08 07:14:39

问题


A smart pointer clears the memory if the pointer gets out of scope. I wanted to adapt this to a file descriptor, like a socket. There you need a user defined deleter, because close() is the function to free the file descriptor (fd) resources.

I found this useful page, unfortunately, most approaches did not work for me. Below is a working solution I found up to now, which is a little nasty. Because uniqu_ptr expects a pointer I created int *fd to store the fd value, therefore, I had to close(*fd) and delete fd in my custom deleter.

(1) Is there a better way?

Options A and B, which are based on the hints provided by the mentioned web page, are much nicer but causing odd compiler errors.

(2) Does anyone know how to correctly use these alternatives?

I'm using Qt Creator 3.0.1 with CONFIG += c++11 option and gcc version 4.8.2

#include "ccommhandler.h"

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <memory>

#include <qdebug.h>

//for Option A and B
struct CloseHandleDeleter {
    typedef int pointer;
    void operator()(int handle) const
    {
    }
};

//custom deleter, working
class MyComplexDeleter
{

public:
    MyComplexDeleter() {}

    void operator()(int* ptr) const
    {
        qDebug() << "Deleting ";
        close(*ptr);
        delete ptr;
    }
};

CCommHandler::CCommHandler()
{
    //Option A doesn't work
    //std::unique_ptr<int, CloseHandleDeleter> file( socket(AF_INET, SOCK_STREAM, 0) );
    //Option B doesn't work
    //std::unique_ptr<int, int()(int)> filePtr(  socket(AF_INET, SOCK_STREAM, 0) , close);

    MyComplexDeleter deleter;
    int *fd = new int;
    *fd = socket(AF_INET, SOCK_STREAM, 0);
    std::unique_ptr<int, MyComplexDeleter> p( fd , deleter);

}

Edit:

The posted answer by Nevin is right, it solves my initial problem.

The comment of learnvst caused to rethink my problem, and I have to say I may made it much more complex than needed, because the following simple class should also solve my problem of auto-free the memory of a resource or as in my case, to close the file descriptor:

class SocketHandler
{
   int _fd;
 public:
   SocketHandler(int FD):_fd(FD){}
   ~SocketHandler() { if(_fd!=-1) close(_fd); }

   operator int() const { return _fd; }
};

回答1:


Because fd isn't a pointer, I wouldn't try to pigeonhole it into unique_ptr. Instead, create a custom class whose interface is based on unique_ptr, as in (caution: totally untested):

class unique_fd
{
public:
    constexpr unique_fd() noexcept = default;
    explicit unique_fd(int fd) noexcept : fd_(fd) {}
    unique_fd(unique_fd&& u) noexcept : fd_(u.fd_) { u.fd_ = -1; }

    ~unique_fd() { if (-1 != fd_) ::close(fd_); }

    unique_fd& operator=(unique_fd&& u) noexcept { reset(u.release()); return *this; }

    int get() const noexcept { return fd_; }
    operator int() const noexcept { return fd_; }

    int release() noexcept { int fd = fd_; fd_ = -1; return fd; }
    void reset(int fd = -1) noexcept { unique_fd(fd).swap(*this); }
    void swap(unique_fd& u) noexcept { std::swap(fd_, u.fd_); }

    unique_fd(const unique_fd&) = delete;
    unique_fd& operator=(const unique_fd&) = delete;

    // in the global namespace to override ::close(int)
    friend int close(unique_fd& u) noexcept { int closed = ::close(u.fd_); u.fd_ = -1; return closed; }

private:
    int fd_ = -1;
};


来源:https://stackoverflow.com/questions/29614775/smart-pointer-to-manage-socket-file-descriptor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!