gpt4 book ai didi

c++ - 我是否在这个通用的 unique_ptr<>() 删除器中正确使用了指针类?

转载 作者:太空狗 更新时间:2023-10-29 22:55:35 25 4
gpt4 key购买 nike

我创建了一个通用删除器模板,可用于创建 unique_ptr<>()允许 Deleter 的子类型除了 delete ptr .

它与默认优化标志(即 -O0 )配合使用效果很好,但是,当我使用 -O3T & operator * ()函数以某种方式返回 0而不是 f_pointer内容。

我想确保我们同意编译器中有问题并且我的模板是正确的。以下是一段完整的代码,应该可以在 Ubuntu 16.04 和 Ubuntu 18.04 以及可能支持 C++14 的其他版本下编译(请参阅下面的测试 g++ 版本)。

// RAII Generic Deleter -- allow for any type of RAII deleter
//
// To break compile with:
// g++ --std=c++14 -O3 -DNDEBUG ~/tmp/b.cpp -o b

#include <memory>
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

template<class T, T null_value, class D, D deleter>
class raii_generic_deleter
{
public:
class pointer
{
private:
T f_pointer = null_value;

public:
pointer(T p)
: f_pointer(p)
{
}

pointer(std::nullptr_t = nullptr)
: f_pointer(null_value)
{
}

explicit operator bool () const
{
return f_pointer != null_value;
}

bool operator == (pointer const rhs) const
{
return f_pointer == rhs.f_pointer;
}

bool operator != (pointer const rhs) const
{
return f_pointer != rhs.f_pointer;
}

T & operator * ()
{
return f_pointer;
}
};

void operator () (pointer p)
{
deleter(*p);
}
};


typedef std::unique_ptr<int,
raii_generic_deleter<int, -1, decltype(&::close), &::close>>
raii_fd_t;


int main(int argc, char * argv [])
{
int fd = -1;

{
raii_fd_t safe_fd;

std::cout << "default initialization: safe_fd = " << *safe_fd
<< std::endl;

fd = open("/tmp/abc.tmp", O_RDWR | O_CREAT, 0700);

std::cout << "fd = " << fd << std::endl;

safe_fd.reset(fd);

std::cout << "safe_fd after the reset(" << fd
<< ") = " << *safe_fd << std::endl;
}

if(fd != -1)
{
// assuming the safe_fd worked as expected, this call returns an error
//
int r = close(fd);
int e(errno);

std::cout << "second close returned " << r
<< " (errno = " << e << ")" << std::endl;
}

return 0;
}

(对于原始文件,请参阅 libsnapwebsites 中的 raii_generic_deleter.h)

这是我使用 -O0 时得到的输出(无优化):

default initialization: safe_fd = -1
fd = 3
safe_fd after the reset(3) = 3
second close returned -1 (errno = 9)

在本例中为 *safe_fd调用返回 -13正如预期的那样。这调用模板 T & pointer::operator * ()功能。

使用任何级别的优化(-O1-O2-O3),输出如下所示:

default initialization: safe_fd = 0
fd = 3
safe_fd after the reset(3) = 0
second close returned -1 (errno = 9)

如我们所见,安全文件描述符返回 0而不是 -1初始化后再次0什么时候应该是3 .但是,由于第二次关闭按预期失败,因此析构函数正确关闭了文件。换句话说,文件描述 ( 3) 不知何故为删除者所知并正确使用。

当我以这种方式更新指针运算符时:

        T & operator * ()
{
std::cout << "f_pointer within operator * = " << f_pointer
<< std::endl;
return f_pointer;
}

那么任何优化级别的输出都是正确的:

f_pointer within operator * = -1
default initialization: safe_fd = -1
fd = 3
f_pointer within operator * = 3
safe_fd after the reset(3) = 3
f_pointer within operator * = 3
second close returned -1 (errno = 9)

这可能是因为该特定功能没有得到完全优化。

编译器:

我在 Ubuntu 16.04 上使用普通 g++ 进行了测试

g++ (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609

还有 Ubuntu 18.04

g++ (Ubuntu 7.3.0-16ubuntu3) 7.3.0

我也继续将此报告为 bug on the GNU website .

最佳答案

问题似乎是 unique_ptr::operator* 的 libstdc++ 实现引起的。这是一种非常简化、精简的方式:

struct pointer
{
pointer(int val = -42) : z(val) { }
int z = -42;
int& operator*() { return z; }
};

struct my_unique_ptr
{
pointer rep;
pointer get() { return rep; }
#ifdef PROBLEM
int& operator*() { return *get(); } // libstdc++ implementation
#else
int& operator*() { return *rep; } // libc++ implementation
#endif
};

int main()
{
my_unique_ptr q;
std::cout << *q << "\n";
}

现在非常清楚,libstdc++ 不可能与您的 pointer 实现一起工作,因为它从 operator* 返回对本地临时对象的引用。任何存储自己指针对象的指针都会有同样的问题。

标准方面,这似乎不是 libstdc++ 中的错误。该标准指定 unique_ptr::operator*() 返回 *get(),而 libstdc++ 忠实地做到了这一点。

如果有的话,这是标准中的一个缺陷。

立即修复是停止在您的pointer 类中定义operator*unique_ptr 不需要它(NullablePointer 不需要提供它)。

因为 pointer 实际上只不过是 T 的包装器,为给定常量提供值初始化,定义一个 更有意义运算符 T(),并使用 get() 来“取消引用”相应的 unique_ptr

关于c++ - 我是否在这个通用的 unique_ptr<>() 删除器中正确使用了指针类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51015016/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com