17

我找不到那个问题,这是我面临的一个实际问题。

我有一个文件加载实用程序,它返回std::vector<unsigned char>包含整个文件内容。但是,处理函数需要 contiguos 数组char(并且不能更改 - 它是一个库函数)。由于使用处理函数的类无论如何都会存储数据的副本,因此我想将其存储为vector<char>. 这是可能更具说明性的代码。

std::vector<unsigned char> LoadFile (std::string const& path);

class Processor {
    std::vector<char> cache;
    void _dataOperation(std::vector<char> const& data);

public:
    void Process() {
        if (cache.empty())
            // here's the problem!
            cache = LoadFile("file.txt");

        _dataOperation(cache);
    }
};

此代码无法编译,因为(显然)没有适当的转换。但是,我们可以肯定,临时向量将占用相同数量的内存 (IOW sizeof(char) == sizeof(unsigned char))

天真的解决方案是迭代临时的内容并转换每个字符。我知道在正常情况下,operator= (T&&)会被调用。

在我的情况下,重新解释转换是安全的,因为我确信我只会读取 ASCII 字符。_dataOperation无论如何,任何其他角色都会被抓住。

所以,我的问题是:如何以不涉及复制的方式正确安全地转换临时向量?

如果不可能,我更喜欢安全的复制方式,而不是不安全的非复制方式。我也可以更改LoadFile为返回vector<char>vector<unsigned char>

4

1 回答 1

8

在 C++11 中,[basic.lval]p10 说,

如果程序尝试通过非下列类型之一的泛左值访问对象的存储值,则行为未定义:

  • ...
  • char 或 unsigned char 类型。

(具体位置在其他版本的C++中可能有所不同,但意思是一样的。)

这意味着您可以使用 avector<unsigned char> cache并使用 range 访问其内容[reinterpret_cast<char*>(cache.data()), reinterpret_cast<char*>(cache.data()) + cache.size())。(@Kerrek SB 提到了这一点。)

如果您存储 avector<unsigned char>Processor匹配 的返回类型LoadFile,并且_dataOperation()实际上采用了一个数组char(意思是 aconst char*和一个大小),那么您可以在将参数传递给_dataOperation()

但是,如果专门_dataOperation()获取 avector<char>并且您存储了 a vector<unsigned char> cache,那么您将无法通过它reinterpret_cast<vector<char>&>(cache)。(即@André Puel 是完全错误的。不要听他的。)这违反了别名规则,编译器会在凌晨 2 点试图激怒你的客户。(如果你的编译器的这个版本不能管理它,下一个版本将继续尝试。)

正如您所提到的,一种选择是模板LoadFile()并让它返回(或填充)您想要的类型的向量。另一种是复制结果,其简洁版本再次是reinterpret_cast源向量的.data(). [basic.fundamental]p1 提到“对于字符类型,对象表示的所有位都参与值表示。”,这意味着您不会丢失数据reinterpret_cast。我没有看到一个坚定的保证,即 an 的任何位模式都不会unsigned char导致陷阱 if reinterpret_cast'edto char,但我不知道有任何现代硬件或编译器可以做到这一点。

于 2013-05-20T00:54:01.540 回答