类的只读成员变量

时间:2012-05-24 18:52:47

标签: c++ c++11

受到this答案的启发我正在使用以下解决方案来获取只读成员变量:

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:我创建了一个单元测试,消除了所有其他的东西。我没有性能损失了,太好了,毕竟没有问题。谢谢您的帮助!我已经修复了构造函数,很好的调用。

7 个答案:

答案 0 :(得分:5)

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

正如@MooingDuck所说,你应该改变你的构造函数以使用init list(并且可能也使它明确)。

答案 1 :(得分:3)

使用辅助元函数:

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;

答案 2 :(得分:2)

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

在DEBUG版本中,每当使用该元素时都需要用户定义的转换,但在RELEASE中,转换被删除,这反过来又可以使用不同的用户定义转换,并导致在选择时引发不同的重载。 member属性作为参数传递给函数。

虽然可能不是常见的情况,如果你确实遇到了它,你会有大量的调试痛苦试图确定应用程序在RELEASE中始终失败的原因,但是你无法用你的DEBUG版本调试它......

答案 3 :(得分:1)

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

答案 4 :(得分:0)

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

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! 请记住,您还需要添加按位和一元运算符!这只是一个让你入门的例子

答案 5 :(得分:0)

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

第一个使用私有内嵌

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

    private:
        int i;
}

第二个使用 const const_cast

class A
{
    public:
        const int I;

        void SetI(int newI)
        {
            //Verify newI or something.

            const_cast<int>(I) = newI;
        }
}

答案 6 :(得分:-2)

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

相关问题