智能指针来管理套接字文件描述符

时间:2015-04-13 20:46:17

标签: sockets c++11 smart-pointers

如果指针超出范围,智能指针会清除内存。我想将其改编为文件描述符,如套接字。在那里你需要一个用户定义的删除器,因为close()是释放文件描述符(fd)资源的函数。

我发现了this有用的页面,不幸的是,大多数方法对我都不起作用。下面是我发现的一个工作解决方案,这有点令人讨厌。因为uniqu_ptr需要一个我创建int * fd的指针来存储fd值,所以我必须关闭(* fd)并删除自定义删除器中的fd。

(1)有更好的方法吗?

选项A和B基于上述网页提供的提示,但更好,但会导致奇怪的编译错误。

(2)有谁知道如何正确使用这些替代品?

我使用Qt Creator 3.0.1和CONFIG + = c ++ 11选项和gcc版本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);

}

修改

Nevin的回答是正确的,它解决了我最初的问题。

learnvst的评论引起了重新思考我的问题,我不得不说我可能使它比需要的要复杂得多,因为下面的简单类也应该解决我自动释放资源内存的问题,或者像我的情况,关闭文件描述符:

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

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

1 个答案:

答案 0 :(得分:1)

因为fd不是指针,我不会尝试将其归入unique_ptr。相反,创建一个自定义类,其接口基于unique_ptr,如(警告:完全未经测试):

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;
};