【问题标题】:Accessing the [] operator from a pointer从指针访问 [] 运算符
【发布时间】:2012-01-19 14:22:16
【问题描述】:

如果我定义一个指向定义[] 运算符的对象的指针,是否有直接的方法可以从指针访问该运算符?

例如,在下面的代码中我可以使用指针的-> 运算符直接访问Vec 的成员函数(如empty()),但是如果我想访问[] 运算符我需要首先获取对象的引用,然后调用操作符。

#include <vector>

int main(int argc, char *argv[])
{
    std::vector<int> Vec(1,1);
    std::vector<int>* VecPtr = &Vec;

if(!VecPtr->empty())      // this is fine
    return (*VecPtr)[0]; // is there some sort of ->[] operator I could use?

return 0;
}

我很可能错了,但看起来(*VecPtr).empty() 的效率低于VecPtr-&gt;empty()。这就是为什么我一直在寻找 (*VecPtr)[] 的替代品。

【问题讨论】:

  • 为什么要避开(*VecPtr)[0]?
  • @Rob 编辑是有原因的。我的假设可能是错误的,但这就是我问的原因。
  • (*VecPtr).empty() 和 VecPtr-&gt;empty() 是完全一样的东西(除非 VecPtr 是重载 operator* 和 operator-&gt; 具有冲突含义的东西。
  • 如果VecPtr 是指针类型,那么(*VecPtr).XXX 根据定义等同于VecPtr-&gt;XXX。没有效率损失。如果VecPtr 是实现operator* 和operator[] 的非指针类型,那么您必须检查它们以查看哪个更有效(它们可能相同)。
  • 这个问题是如何获得投票的?它基于最不知情和研究不足的前提之一,对其他人几乎没有价值。

标签: c++ pointers operators


【解决方案1】:

您可以执行以下任何操作:

#include <vector>

int main () {
  std::vector<int> v(1,1);
  std::vector<int>* p = &v;

  p->operator[](0);
  (*p)[0];
  p[0][0];
}

顺便说一句,在 std::vector 的特殊情况下,您也可以选择:p-&gt;at(0),尽管它的含义略有不同。

【讨论】:

  • 最后一个很有趣,你能解释一下引擎盖下发生了什么吗?第一个 [0] 是指指针指向的“第一个元素”吗?类似于向量引用是指向数组开头的指针?
  • @ThekoLekena 确切地说,对于指向完整类型 T 的指针,[] 运算符被定义为访问数组的第 i 个元素(通过计算 sizeof(T) * i)。当然,因为在这种情况下,我们有一个指向 one 向量的指针,所以除了 [0] 之外的任何东西都是未定义的行为。 编辑:不过我不会选择最后一个,因为我觉得它不太惯用。
  • @ancientchild 同意,最后一个不应该作为常规做法。
【解决方案2】:
return VecPtr->operator[](0);

...会成功的。但实际上,(*VecPtr)[0] 表单看起来更好,不是吗?

【讨论】:

    【解决方案3】:

    (*VecPtr)[0] 完全可以,但如果你愿意,可以使用at 函数:

    VecPtr->at(0);
    

    请记住,如果索引不在范围内,这(与 operator[] 不同)将引发 std::out_of_range 异常。

    【讨论】:

      【解决方案4】:

      还有另一种方式,你可以使用对对象的引用:

      #include <iostream>
      #include <vector>
      using namespace std;
      
      int main()
      {
          vector<int> v = {7};
          vector<int> *p = &v;
      
          // Reference to the vector
          vector<int> &r = *p;
          cout << (*p)[0] << '\n'; // Prints 7
          cout <<    r[0] << '\n'; // Prints 7
      
          return 0;
      }
      

      这样,r 与v 相同,您可以将所有出现的(*p) 替换为r。

      警告:这仅在您不会修改指针(即更改它指向的对象)时才有效。

      考虑以下几点:

      #include <iostream>
      #include <vector>
      using namespace std;
      
      int main()
      {
          vector<int> v = {7};
          vector<int> *p = &v;
      
          // Reference to the vector
          vector<int> &r = *p;
          cout << (*p)[0] << '\n'; // Prints 7
          cout <<    r[0] << '\n'; // Prints 7
      
          // Caveat: When you change p, r is still the old *p (i.e. v)
          vector<int> u = {3};
          p = &u; // Doesn't change who r references
          //r = u; // Wrong, see below why
          cout << (*p)[0] << '\n'; // Prints 3
          cout <<    r[0] << '\n'; // Prints 7
      
          return 0;
      }
      

      r = u; 是错误的,因为您不能更改引用: 这将修改r 引用的向量 (v) 而不是引用另一个向量 (u)。 所以,同样,这只有在指针在仍然使用引用时不会改变的情况下才有效。

      示例只需要 C++11 因为vector&lt;int&gt; ... = {...};

      【讨论】:

      • r = u; 很好,它将在两个向量之间进行分配;这与p无关
      • 这就是我所说的“错误”。引用我自己的话,“你可以用r替换所有出现的(*p)”,但是“这只有在你不修改指针的情况下才有效”,因为没有办法改变r,因为你会改变值的*p。 r = u; “将修改 r 引用的向量,而不是引用另一个向量”——它不会产生预期的效果。
      • r = u; 无论你以后是否修改指针都会有同样的效果
      • 是的,但我不明白你为什么这么说。同样,“错误”是指它不会像p = ... 那样做。我说的是用r 替换所有出现的*p。但是如果你的代码中有p = ...,那么用r = ... 替换p = ... 是错误的。
      【解决方案5】:

      您可以将其用作VecPrt-&gt;operator [] ( 0 ),但我不确定您是否会觉得它不那么晦涩。

      【讨论】:

        【解决方案6】:

        值得注意的是,在 C++11 中,std::vector 有一个成员函数 'data',它返回一个指向底层数组的指针(包括 const 和非 const 版本),允许您编写以下内容:

        VecPtr->data()[0];
        

        这可能是

        VecPtr->at(0);
        

        这会产生很小的运行时开销,但更重要的是,它的使用意味着您在调用它之前没有检查索引的有效性,这在您的特定示例中是不正确的。

        更多详情请见std::vector::data。

        【讨论】:

          【解决方案7】:

          由于范围检查,人们建议您使用-&gt;at(0)。但这是我的建议(有其他观点):

          切勿使用-&gt;at(0)!它真的很慢。你会因为懒得不自己检查范围而牺牲性能吗?如果是这样,您不应该使用 C++ 编程。

          我认为(*VecPtr)[0] 可以。

          【讨论】:

          • 为什么 at(0) 很慢?
          猜你喜欢
          • 2017-07-18
          • 2015-12-28
          • 2020-12-24
          • 2011-02-23
          • 2023-04-08
          • 1970-01-01
          • 1970-01-01
          • 2013-07-22
          相关资源
          最近更新 更多