类的只读成员变量


受到

这个答案的启发,我正在对只读成员变量使用以下解决方案:

template <class T, class OWNER>
class readonly
{
    friend OWNER;
public:
    explicit readonly(const T &t) : m_t(t)
    {
    }
    ~readonly()
    {
    }
    operator const T&() const
    {
        return m_t;
    }
private:
    T& operator =(const T &t)
    {
        m_t = t; 
        return m_t;
    }
    T m_t;
};

效果很好,为了稍微优化性能,我像这样使用它:

class A
{
public:
    A()
    {
    }
    ~A()
    {
    }
#ifdef _DEBUG     // DON'T USE THIS SWITCH, SEE ANSWERS BELOW!
    readonly<int, A> m_x, m_y;
#else
    int m_x, m_y;
#endif
};

但是,我很想消除预编译器开关,该开关检查我们是否正在进行调试或发布构建......有没有人看到使用宏或聪明的模板技巧的解决方案?

编辑:我已经在循环中检查了性能,它使用VS2010产生约15~20%的开销。它不会导致相同的代码,启用自动内联。

编辑#2:我创建了一个单元测试,消除了所有其他内容。我不再有性能损失了,这么大,毕竟没有问题。感谢您的帮助!我已经修复了构造函数,很好的调用。

您的优化是无用的,并且会产生完全相同的代码。所有readonly都是微不足道的,并且将被内联,从而消除了使用原始 T 可能产生的任何开销。因此,解决方案是不修复不存在的问题,而只使用readonly<int, A>,无论这是否是调试版本。

正如@MooingDuck所指出的,你应该将构造函数更改为使用 init list(并且可能也使其显式)。

使用辅助元函数:

template< typename T, typename Owner >
struct make_read_only
{
#ifdef _DEBUG
    typedef readonly< T, Owner > type;
#else
    typedef T type;
#endif
};

并将您的会员声明更改为:

make_read_only< int, A >::type;

你的方法对我来说是一个很大的问题:它可以在调试和发布模式下生成不同的代码。在这里,我考虑的不是性能,而是语义。如果优化器无法生成等效的二进制文件,我会感到惊讶。

在 DEBUG 版本中,每当使用该元素时都需要用户定义的转换,但在 RELEASE 中,该转换被丢弃,这反过来又允许使用不同的用户定义转换,并导致在将成员属性作为参数传递给函数时选取不同的重载。

虽然可能不是一个常见的情况,但如果你确实遇到了它,你会有很多调试痛苦,试图确定为什么应用程序在 RELEASE 中总是失败,但你不能用你的 DEBUG 版本调试它......

const 修饰符没有性能方面。如果有一个好的优化器,你的调试和发布版本将产生相同的代码。

这是一个稍微不同的看法。如果你想要一个只读变量,但不希望客户端必须更改他们访问它的方式,请尝试以下模板化类:

template<typename MemberOfWhichClass, typename primative>                                       
class ReadOnly {
    friend MemberOfWhichClass;
public:
    inline operator primative() const                 { return x; }
    template<typename number> inline bool   operator==(const number& y) const { return x == y; } 
    template<typename number> inline number operator+ (const number& y) const { return x + y; } 
    template<typename number> inline number operator- (const number& y) const { return x - y; } 
    template<typename number> inline number operator* (const number& y) const { return x * y; }  
    template<typename number> inline number operator/ (const number& y) const { return x / y; } 
    template<typename number> inline number operator<<(const number& y) const { return x <<y; }
    template<typename number> inline number operator>>(const number& y) const { return x >> y; }
    template<typename number> inline number operator^ (const number& y) const { return x ^ y; }
    template<typename number> inline number operator| (const number& y) const { return x | y; }
    template<typename number> inline number operator& (const number& y) const { return x & y; }
    template<typename number> inline number operator&&(const number& y) const { return x &&y; }
    template<typename number> inline number operator||(const number& y) const { return x ||y; }
    template<typename number> inline number operator~() const                 { return ~x; }
protected:
    template<typename number> inline number operator= (const number& y) { return x = y; }       
    template<typename number> inline number operator+=(const number& y) { return x += y; }      
    template<typename number> inline number operator-=(const number& y) { return x -= y; }      
    template<typename number> inline number operator*=(const number& y) { return x *= y; }      
    template<typename number> inline number operator/=(const number& y) { return x /= y; }      
    template<typename number> inline number operator&=(const number& y) { return x &= y; }
    template<typename number> inline number operator|=(const number& y) { return x |= y; }
    primative x;                                                                                
};      

使用示例:

class Foo {
public:
    ReadOnly<Foo, int> x;
};
现在您可以访问 Foo.x

,但无法更改 Foo.x!请记住,您还需要添加按位运算符和一元运算符!这只是帮助您入门的示例

我更喜欢这两个解决方案。

第一个使用私有内联

class A
{
    public:
        inline int GetI();
        {
            return i;
        }
    private:
        int i;
}

第二个使用常量const_cast

class A
{
    public:
        const int I;
        void SetI(int newI)
        {
            //Verify newI or something.
            const_cast<int>(I) = newI;
        }
}

我不是 100% 确定,但看起来不可能用模板做到这一点。因为模板无法读取预处理器变量。为了使您的代码更具可读性,您可以定义像 READONLY_INT 这样的宏,并在其他 .h 文件中声明它。

最新更新