【问题标题】:overload array operator with templates and pointers使用模板和指针重载数组运算符
【发布时间】:2011-10-03 08:02:06
【问题描述】:

以下代码可在 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
}

【问题讨论】:

标签: c++ templates pointers operator-overloading


【解决方案1】:

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

您可能希望按值返回。

编辑

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

实时查看解决方案

注意:aPtr 未初始化还有另一个问题。我为此提出了一个简单的构造函数。 _你可能想从其他地方初始化它你需要

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

.

#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
}

【讨论】:

  • 这对于参考版本来说还不够,因为 getVal1getVal2 返回值,而不是参考,所以这些也必须更改。
  • 第一个解决方案给simplerpriv.cc:33:14: error: lvalue required as left operand of assignment',第二个给simplerpriv.cc:23:45: error: invalid initialization of non-const reference of type ‘int&amp;’ from an rvalue of type ‘int’
  • @Jeremiah:如果你想通过引用返回,你需要从 getVal1() 等返回引用。目前,这是返回值。
  • @LucDanton:一路走来,使用 setter 解决了问题。见ideone.com/oxslQ
  • @sehe 谢谢。 T&amp; getVal1() 摆脱了编译器警告,但 g++ 二进制文件仍然存在段错误。我会更新问题。
【解决方案2】:

如果你想通过引用返回,那么你的 A::getValX() 函数也应该通过引用返回,并且你在 B::operator 中的 res 变量也应该是 T& 而不是 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 值的简单副本,仅在声明它的范围内(在本例中为函数)内有效。所以你需要在这里参考。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-02
    • 1970-01-01
    • 1970-01-01
    • 2014-12-24
    • 1970-01-01
    • 2018-08-03
    相关资源
    最近更新 更多