直接访问唯一的类数据成员

时间:2018-03-23 07:37:55

标签: c++ c++11 templates memory-address

我有一个具有唯一公共数据成员的类,它是一个内置类型:

class foo {
public:
    int data;

    foo(int dataIn) : data(dataIn) {}
    virtual ~foo() {}

    // Some other class methods
protected:
    // Some internal helper class methods
};

在其他课程中,我想使用memcpy方法:

template<typename T>class bar {
protected:
    T data;
public:
    bar() {}
    virtual ~bar() {}

    void read(unsigned char* readBuff, const std::size_t &readSize) {
        // Some stuff
        std::memcpy(readBuff, &(this->data), readSize);
        // Some stuff
    }
};

如果bar是内置类型或T的实例,则foo可以使用{/ 1}}。

但是,foo data实例中的T是bar,因此是foo,我确保从&(this->data)指向的元素中读取data中的foo

当我运行时:

foo x(12);
std::cout << sizeof(foo);

我得到4,所以foo似乎正好是int的大小,所以我自然会认为直接读/写x即使没有指定x.data也会写入数据。这是真的吗?

我需要兼容C ++ 11。

3 个答案:

答案 0 :(得分:4)

没有

对于具有虚函数的类,通常编译器会在类的开头插入一些元数据。您不能假设实例的地址也是其第一个成员的地址。

您可以使用if constexpr区分这两种情况:

    if constexpr ( std::is_same_v<std::decay_t<T>, foo> ) {
        std::memcpy(readBuff, &(this->data.data), readSize);
    } else {
        std::memcpy(readBuff, &(this->data), readSize);
    }

答案 1 :(得分:3)

没有

具有虚拟成员的任意类型的布局是实现定义的。您无法保证在foo中偏移量为data

您可以为bar完全专门化foo

template<>class bar<foo> {
protected:
    foo data;
public:
    bar() {}
    virtual ~bar() {}

    void write(unsigned char* readBuff, const std::size_t &readSize) {
        // Some stuff
        std::memcpy(readBuff, &(this->data.data), readSize);
        // Some stuff
    }
};

如果bar的其余部分重复出现问题,您可以编写帮助模板

template<typename T> bar_helper
{
    void* operator()(T & data) { return &data; }
}

template<> bar_helper<foo>
{
    void* operator()(foo & data) { return &data.data; }
}

template<typename T>
void bar<T>::write(unsigned char* readBuff, const std::size_t &readSize) {
    // Some stuff
    bar_helper<T> helper;
    std::memcpy(readBuff, helper(this->data), readSize);
    // Some stuff
}

答案 2 :(得分:0)

经过多次尝试,我发现了另一种实现它的方法,而不必像在@Caleth的解决方案中那样在read()中实例化一个新的helper对象(虽然非常好),所以应该这样做有更好的表现:

class foo {
public:
    int data;

    foo(int dataIn) : data(dataIn) {}
    virtual ~foo() {}

    // Some other class methods
protected:
    // Some internal helper class methods
};

template<bool ISFOO> struct IsFoo_ {
    enum {
        IS_FOO_ = ISFOO
    };
};

template<typename T>class bar {
protected:
    T data;
public:
    bar() {}
    virtual ~bar() {}

    struct CRV {
        enum {
            USES_FOO = std::is_same<T, foo>::value
        };
    };

    void* getCopyable() {
        return getCopyable_<CRV::USES_FOO>();
    }

    void read(unsigned char* readBuff, const std::size_t &readSize) {
        // Some stuff
        std::memcpy(readBuff, this->getCopyable(), readSize);
        // Some stuff
    }

private:
    // Caller method
    template<bool ISFOO> inline void* getCopyable_() {
        return getCopyable_(IsBitVector_<ISFOO>());
    }
    // Generic method
    template<bool ISFOO> inline void* getCopyable_(IsFoo_<ISFOO>) {
        return nullptr;
    }
    // Specializations
    inline void* getCopyable_(IsFoo_<true>) {
        return reinterpret_cast<void*>(&(this->data.data));
    }
    inline void* getCopyable_(IsFoo_<false>) {
        return reinterpret_cast<void*>(&(this->data));
    }
};