具有POSIX文件描述符对象的C 复制构造函数

C++ Copy constructor of object owning a POSIX file descriptor

本文关键字:复制 构造函数 对象 POSIX 文件 描述 具有      更新时间:2023-10-16

我需要将拥有POSIX文件描述符的C 对象放在向量中。我有一个用来创建对象的filepath的向量。这是我的代码:

main.cpp

std::vector<MightyObject> mightyObjects;
std::vector<const char*> paths = {"awesomePath1", "awesomePath2"};
for (std::vector<const char*>::iterator it = paths.begin(); it != paths.end(); ++it)
{
    mightyObjects.emplace_back(MightyObject(*it));
}

MightyObject.cpp

MightyObject::MightyObject(const char* path)
{
   this->fd = open(path, O_RDWR | O_NONBLOCK);
}
MightyObject::~MightyObject()
{
    close(this.fd);
}
MightyObject::MightyObject(const MightyObject& obj)
{
    this->fd = dup(obj.fd);
}
MightyObject& MightyObject::operator=(const MightyObject& other)
{
    this->fd = dup(other.fd);
    return *this;
}

在MightyObject中,我的对象有错误的文件描述符...

我在做什么错?

所示的代码应包含正确的文件描述符,尽管它会将描述符泄漏到分配中。要修复它,您应该将其更改为:

  • 修复分配运算符中的泄漏;
  • 处理自我分配;
  • 实现A 移动构造函数以优化移动(并且因为此类是移动构造的好处的教科书示例);
  • 处理错误。

例如(未经测试):

static int safe_dup(int fd) {
    int copy = dup(fd); 
    if (copy < 0)
        throw std::runtime_error(strerror(errno));
    return copy;
}
MightyObject::MightyObject(const char* path) {
    this->fd = open(path, O_RDWR | O_NONBLOCK);
    if (this->fd == -1)
        throw std::runtime_error(strerror(errno));
}
MightyObject::~MightyObject() {
    if (this->fd != -1)
        close(this->fd);
}
MightyObject::MightyObject(const MightyObject& other) {
    this->fd = safe_dup(other.fd);
}
MightyObject& MightyObject::operator=(const MightyObject& other) {
    if (this != &other) {
        close(this->fd);
        this->fd = safe_dup(other.fd);
    }
    return *this;
}
MightyObject::MightyObject(MightyObject&& other) {
    // "move" file descriptor from OTHER to this: no duping is needed,
    // we just take the descriptor and set the one in OTHER to -1, so
    // it doesn't get closed by OTHER's destructor.
    this->fd = other.fd;
    other.fd = -1;
}
MightyObject& MightyObject::operator=(MightyObject&& other) {
    // move assignment operator
    close(this->fd);
    this->fd = other.fd;
    other.fd = -1;
}

一旦了解了移动语义,就可以通过部署副本和交换成语来减少操作员之间的代码重复。

请注意,以上应理解为一种编码和理解练习。在生产中,您可能不想在复制对象时分配新的文件描述符。更好的设计将使文件只移动,并将MightyObject作为std::shared_ptr<Handle>实现。这将完全避免使用dup并摆弄复制构造函数,分配运算符等,因为所有这些都将由shared_ptr处理。