0

我正在重构一些遗留代码,它将文件中的一些二进制数据读取到结构中。我想到将变量更改为 std::optional 可以确保变量在使用之前实际读取(初始化)。但是文件读取代码需要变量的地址。有没有办法(一种预期的方式不是黑客)告诉 std::optional “给我一个指向你未初始化的T 的指针,这样我就可以写那个内存的内容”和“继续把你的状态从空更改为值- 现在满了”?

(也就是说,不是分配默认 T(如果 T 没有默认构造函数怎么办)然后获取默认构造值的地址。)

简化示例:

struct FILE_HEADER { /* some data members... */ };

class FileFrobulator
{
private:
   FILE_HEADER fileHead;

public:
   void called_first(IFileReader* reader)
   {
       // ...
       reader->read(&fileHead, sizeof(FILE_HEADER));
       // ...
   }

   void called_later(IFileReader* reader)
   {
      // ...
      // use fileHead.foo, fileHead.bar, etc. while reading rest of file
      // ...
   }
};

问题是如果我将成员更改std::optional<FILE_HEADER> fileHead;为什么,那么我要为当前读取的行更改什么reader->read(&fileHead, sizeof(FILE_HEADER));

我可以这样做:

fileHead = FILE_HEADER();
reader->read(&*fileHead, sizeof(FILE_HEADER));

您之前可能已经反对,在 std::optional 中获取未初始化 T 的地址并将可选设置为不再为空的功能会冒着意外留下可选标记值的风险,而如果用户没有初始化,则仍然未初始化。 t 实际上写内存。但是请注意,上面的代码示例运行类似,尽管风险较小:如果 reader->read() 抛出,则可选项将不再为空,但也无法使用。默认构造的 T 可以说比未初始化的 T 更好,但是如果 FILE_HEADER 是 C 结构(在本例中是),它的成员仍然未初始化!

也许这样更好:

FILE_HEADER temp;
reader->read(&temp, sizeof(FILE_HEADER));
fileHead = temp;

但这两者都涉及冗余初始化和/或复制(可能由编译器优化)。

4

1 回答 1

0

有没有办法(一种预期的方式不是黑客)告诉 std::optional “给我一个指向你未初始化的 T 的指针,这样我就可以写那个内存的内容”和“继续把你的状态从空更改为值- 现在满了”?

这两件事都是谎言。

optional<T>没有T, 初始化与否,因此您将获得指向不存在的对象的指针/引用。并且 an 的状态optional<T>应该反映 a 是否T存在于 中optional<T>。由于复制位本身不会导致 aT出现,除非用户直接创建 a T,否则它将不存在。所以假装 aT存在而它不存在也是错误的。

要做你想做的事情,你应该有一个返回一个函数optional<FILE_HEADER>

fileHead = readFileHeader(reader);

如果读取函数抛出,则FileFrobulator永远不会设置值。如果您愿意,您甚至可以将其设为 lambda 函数:

fileHead = [](IFileReader* reader) {
  std::optional<FILE_HEADER> ret(std::in_place);
  reader->read(&*ret, sizeof(FILE_HEADER));
  return ret;
}(reader);
于 2020-03-19T15:27:57.450 回答