带有模板和指针的重载数组运算符

时间:2011-10-03 08:02:07

标签: c++ templates pointers operator-overloading

以下代码在clang ++ - 2.9和g ++ - 4.6上编译(没有警告)。但是,g ++二进制文件Seg Faults,而clang ++二进制文件按预期运行。

重载[]时,通过指针访问模板类数据成员的正确方法是什么?

以下是代码:

#include <iostream>
template <typename T>
    class A {
    private:
    T val1;
    T val2;

    public:
    T& getVal1() { return val1; }
    void setVal1(T aVal) { val1 = aVal; }
    T& getVal2() { return val2; }
    void setVal2(T aVal) { val2 = aVal; }
};

template <typename T>
    class B {
    private:
    A<T>* aPtr;

    public:
    A<T>* getAPtr() { return aPtr; }
    T& operator[](const int& key) {
    if(key == 0) { T& res = getAPtr()->getVal1();
        return res; }
    else { T& res = getAPtr()->getVal2();
        return res; }
    }
};

int main()
{
    B<int> foo;
    foo[0] = 1;
    int x = foo[0];
    std::cout << foo[0] << " " << x << std::endl; // 1 1
}

2 个答案:

答案 0 :(得分:0)

您正在返回对局部变量(res)的引用。从operator []返回后,引用无效。它可能会被其他东西覆盖。真正发生的是未定义:这就是允许编译器吃掉你的孩子或长胡子的原因:未定义的行为

您可能希望按值返回。

修改

由于您有一个setter,因此您不需要参考:在 http://ideone.com/oxslQ

中查看解决方案

注意:aPtr未初始化时存在另一个问题。我为此提出了一个简单的构造函数。 _您可能希望从其他地方 OR 初始化

  • 赋值和复制构造函数
  • 或使用shared_ptr for aPtr

#include <iostream>

template <typename T>
class A
{
private:
    T val1;
    T val2;

public:
    T getVal1()
    {
        return val1;
    }
    void setVal1(T aVal)
    {
        val1 = aVal;
    }
    T getVal2()
    {
        return val2;
    }
    void setVal2(T aVal)
    {
        val2 = aVal;
    }
};

template <typename T>
class B
{
private:
    A<T>* aPtr;
    B(const B&);            // TODO , disallow for now
    B& operator=(const B&); // TODO , disallow for now

public:
    B() : aPtr(new A<T>()) {}
    ~B() { delete aPtr; }

    A<T>* getAPtr()
    {
        return aPtr;
    }
    T operator[](const int& key)
    {
        if(key == 0)
        {
            T res = getAPtr()->getVal1();
            return res;
        }
        else
        {
            T res = getAPtr()->getVal2();
            return res;
        }
    }
};

int main()
{
    B<int> foo;
    foo.getAPtr()->setVal1(1);
    int x = foo[0];
    std::cout << foo[0] << " " << x << std::endl; // 1 1
}

答案 1 :(得分:0)

如果你想通过ref返回,那么你的A :: getValX()函数也应该由ref返回,而你在B ::运算符中的res变量也应该是T&amp;而不是T:

#include <iostream>
template <typename T>
    class A {
    private:
    T val1;
    T val2;

    public:
    T& getVal1() { return val1; }
    void setVal1(T aVal) { val1 = aVal; }
    T& getVal2() { return val2; }
    void setVal2(T aVal) { val2 = aVal; }
};

template <typename T>
    class B {
    private:
    A<T>* aPtr;

    public:
    A<T>* getAPtr() { return aPtr; }
    T& operator[](const int& key) {
        if(key == 0) { T& res = getAPtr()->getVal1();
            return res; }
        else { T& res = getAPtr()->getVal2();
            return res; }
    }
};

int main()
{
    B<int> foo;
    foo[0] = 1;
    int x = foo[0];
    std::cout << foo[0] << " " << x << std::endl; // 1 1
}

(注意它在运行时仍然会崩溃,因为aPtr没有在任何地方初始化。)

您的原始代码返回对局部变量res的引用,而不是您可能想要的A :: val1 / A :: val2。如果res是非引用变量,那么它将是val1 / val2值的简单 copy ,它仅对声明它的作用域(在本例中为函数)内有效。所以你需要一个参考。