包装二进制缓冲区 - 可能没有无关的移动/复制?

时间:2017-03-27 23:13:04

标签: c++ c++11 binary buffer c++14

公平警告,我是C ++新手。所以,我的部分或全部假设可能都有问题。

请考虑以下事项:

#include <cstddef>
#include <cstdio>

template <typename T>
class StaticData {
private:
    const T* data = nullptr;
    std::size_t size;
public:
    StaticData(const T* data, std::size_t size) : data(data), size(size) { }
    const T* GetData() {
        return this->data;
    }
    std::size_t GetSize() {
        return this->size;
    }
};

const unsigned char foo[] = { 0x66, 0x6F, 0x6F };
// Possible to initialize this class with data directly?
StaticData<unsigned char> SDFoo = StaticData<unsigned char>(foo, sizeof(foo));

int main() {
    std::printf("%p (%lu)\n", foo, sizeof(foo));
    std::printf("%p (%lu)\n", SDFoo.GetData(), SDFoo.GetSize());
}

使用此代码,我将foo包装在包含数据及其值的(不完整)类中。我没有兴趣修改包含的数据,我只是想要一个安全的包装器,它的大小始终可用。我首先尝试了std::array,但它有一个令人遗憾的副作用,即将大小作为其类型的一部分,我不能将不同大小的数组放在容器中,例如std::unordered_map

这种方法的唯一问题是foo仍然在全球范围内闲置。为了安全起见,我更倾向于容器类SDFoo是唯一可见的东西(也许是Foo)。但是,我无法找到摆脱foo的方法,而不会在静态初始化时引入不必要的移动或复制整个缓冲区。

有什么想法吗?

编辑:要清楚,我想知道是否有办法以某种方式摆脱额外的foo变量。

2 个答案:

答案 0 :(得分:2)

从全局内存中消除foo变量的唯一方法(我知道)是在StaticData对象本身内部分配数据的副本。您可以使用std::shared_ptr(允许您复制StaticData而不制作其数据的额外副本)和std::initializer_list来帮助您,例如:

#include <initializer_list> 
#include <memory> 

template <typename T>
class StaticData {
private:
    const T* m_data;
    std::size_t m_size;
    std::shared_ptr<T[]> m_storage;

public:
    StaticData(const T* data, std::size_t size)
        : m_data(data), m_size(size)
    {
    }

    StaticData(const std::initializer_list<T> &data)
        : m_storage(new T[data.size()]), m_data(m_storage.get()), m_size(data.size())
    {
        std::copy(data.begin(), data.end(), m_storage.get());
    }

    const T* GetData() const
    {
        return m_data;
    }

    std::size_t GetSize() const
    {
        return m_size;
    }
};

StaticData<unsigned char> SDFoo({ 0x66, 0x6F, 0x6F });

void bar(const char *str)
{
    StaticData<char> SDBar(str, strlen(str));
    std::printf("SDBar: %p (%lu)\n", SDBar.GetData(), SDBar.GetSize());
}

int main()
{
    std::printf("SDFoo: %p (%lu)\n", SDFoo.GetData(), SDFoo.GetSize());
    bar("baz");
    return 0;
}

答案 1 :(得分:1)

那么您正在寻找的是对任意数据的const视图,其中数据本身是私有的?也许是这样的事情:

// foo.h
extern StaticData<const unsigned char> foo;

// foo.cpp
#include "foo.h"
unsigned char foo_data[] = {0xde, 0xad, 0xbe, 0xef};
StaticData<const unsigned char> foo(foo_data, sizeof(foo_data));

这样可以隐藏实际数据,因为它只能从源文件中看到,并且唯一导出的访问方式是通过const视图。