使用模板和指针重载数组运算符

发布于 2024-12-08 01:49:07 字数 971 浏览 0 评论 0原文

以下代码在 clang++-2.9 和 g++-4.6 上编译(没有警告)。但是,g++ 二进制文件出现段错误,而 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
}

The following code compiles (without warnings) on both clang++-2.9 and g++-4.6. However, the g++ binary Seg Faults, while the clang++ binary runs as intended.

What is the proper way to access template class data members through pointers when overloading []?

Here's the code:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

零時差 2024-12-15 01:49:07

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

你可能想按值返回。

编辑

由于您有设置器,因此不需要参考:请在http://ideone.com/oxslQ

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

  • 赋值和复制构造函数
  • 或使用shared_ptr作为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
}

You are returning a reference to a local variable (res). The reference won't be valid after returning from operator[]. It could be overwritten by other stuff. What really happens is Undefined: that is why compilers are allowed to eat your children or grow a moustache: Undefined Behaviour

You probably want to return by value.

Edit

Since you have a setter, you don't need the reference: See the solution live at http://ideone.com/oxslQ

Note: there was another problem with aPtr not being initialized. I proposed a simple constructor for that. _You might want to initialize this from elsewhere OR you need

  • assignment and copy constructors
  • or use a 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
}
霞映澄塘 2024-12-15 01:49:07

如果你想通过 ref 返回,那么你的 A::getValX() 函数也应该通过 ref 返回,并且 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 值的简单副本,仅在声明它的范围(在本例中为函数)内有效。所以你需要一个参考。

If you want to return by ref, then your A::getValX() functions should also return by ref, and your res variable inside B::operator should also be T& instead of 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
}

(Note that it will still crash at runtime, since aPtr isn't initialized anywhere.)

Your original code returns a reference to the local variable res, not to A::val1 / A::val2 as you probably intended. If res is a non-reference variable, then it will be a simple copy of the val1 / val2 value, that is only valid for inside the scope (in this case the function) where it was declared. So you need a reference here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文