【问题标题】:When to use pointers in C++何时在 C++ 中使用指针
【发布时间】:2011-01-11 06:39:10
【问题描述】:

我刚开始学习 C++ 中的指针,我不太确定何时使用指针以及何时使用实际对象。

例如,在我的一个作业中,我们必须构造一个 gPolyline 类,其中每个点都由一个 gVector 定义。现在我的 gPolyline 类的变量如下所示:

private:
vector<gVector3*> points;

如果我有 向量 点,会有什么不同?此外,是否有关于何时使用指针的一般经验法则?提前致谢!

【问题讨论】:

  • 内存副本是最大的影响。如果您谈论的是三个整数,则可以忽略不计。
  • @mloskot - 如果您愿意检查一下,您会发现 Alice 只问了四个问题并接受了其他三个问题的答案。所以她清楚地知道 SO 的工作原理,并且大概正在评估答案以找出最能回答她的问题的答案。
  • @Neil & @ChrisF - 我并不是说有任何要求。等待超过 1-2 小时是对的。向爱丽丝致敬。

标签: c++ vector pointers


【解决方案1】:

一般的经验法则是在需要时使用指针,尽可能使用值或引用。

如果您使用vector&lt;gVector3&gt;,插入元素将复制这些元素,并且这些元素将不再连接到您插入的项目。当您存储指针时,向量仅引用您插入的对象。

因此,如果您希望多个向量共享相同的元素,以便元素的变化反映在所有向量中,则需要向量包含指针。如果您不需要此类功能,存储值通常会更好,例如,它可以让您不必担心何时删除所有这些指向的对象。

【讨论】:

    【解决方案2】:

    在现代 C++ 中通常要避免使用指针。如今,指针的主要目的围绕着这样一个事实,即指针可以是多态的,而显式对象则不是。

    当你现在需要多态性时,最好使用智能指针类——比如std::shared_ptr(如果你的编译器支持 C++0x 扩展),std::tr1::shared_ptr(如果你的编译器不支持 C++ 0x 但确实支持 TR1) 或 boost::shared_ptr

    【讨论】:

    • 我不知道您所说的“现代 C++”是什么意思,但在我从事的许多大型项目中,我不得不将代码从 STL_Struct&lt;object&gt; 迁移到 STL_Struct&lt;object *&gt; :)有时您需要一个指向对象而不是对象本身的指针,原因我在上面的回答中阐明了......但我承认通常不需要指针。
    • “现代 C++”是指 C++03 标准或 ANSI/ISO 标准化 C++。一些较旧的编译器没有完全实现标准,需要指针来修补这些编译器的不一致性。
    【解决方案3】:

    一般来说,在必要时使用指针是个好主意,但在可能的情况下使用引用或对象对象(想想值)。

    首先您需要知道gVector3 是否满足标准容器的要求,即gVector3 类型是否可复制和可分配。如果gVector3 也是默认可构造的,这很有用(请参阅下面的更新说明)。 假设是这样,那么你有两个选择,将gVector3的对象直接存储在std::vector

    std::vector<gVector3> points;
    points.push_back(gVector(1, 2, 3)); // std::vector will make a copy of passed object
    

    或手动管理 gVector3 对象的创建(以及销毁)。

    std::vector 点; points.push_back(新 gVector3(1, 2, 3)); //...

    当不再需要 points 数组时,请记住遍历所有元素并对其调用 delete 运算符。

    现在,您可以选择是否可以将gVector3 作为对象来操作(您可以假设将它们视为值或值对象),因为(如果,请参阅上面的条件)由于复制构造函数和赋值运算符的可用性,以下操作是可能的:

    gVector3 v1(1, 2, 3);
    gVector3 v2;
    v2 = v1; // assignment
    gVector3 v3(v2); // copy construction
    

    或者您可能想要或需要使用 new 运算符在 动态存储 中分配 gVector3 的对象。这意味着,您可能希望或需要自行管理这些对象的生命周期。

    顺便说一句,你可能还想知道When should I use references, and when should I use pointers?

    更新:这是对默认可构造性注释的解释。感谢 Neil 指出最初并不清楚。正如 Neil 正确注意到的那样,C++ 标准并不要求它,但是我指出了这个特性,因为它是一个重要且有用的特性。如果类型 T 不是默认可构造的,C++ 标准没有要求,那么用户应该注意我尝试在下面说明的潜在问题:

    #include <vector>
    struct T
    {
        int i;
        T(int i) : i(i) {}
    };
    int main()
    {
        // Request vector of 10 elements
        std::vector<T> v(10); // Compilation error about missing T::T() function/ctor
    }
    

    【讨论】:

    • 您对可复制和可分配的要求是正确的-您对默认可构造的要求是错误的-没有这样的要求。
    • +1 非常好。我已经更新了我的答案以使其更清楚。谢谢!
    • 你可以说:std::vector v(10, T(0));我也犯了这个错误——你可以在punchlet.wordpress.com/2009/12/03/letter-the-third的默认构造函数上看到我的博客条目。
    • 是的,这是正确的,但与 T 类型(或您博客中的类似类型)的这个特定示例密切相关。但是,有时类型更复杂,模仿虚拟或默认可构造性并不容易,甚至不可能。
    【解决方案4】:

    您可以使用指针或对象 - 归根结底是一样的。

    如果你有一个指针,你需要以任何方式为实际对象分配空间(然后指向它)。归根结底,如果您有一百万个对象,无论您是存储指针还是对象本身,您都会在内存中分配一百万个对象的空间。

    何时改用指针?如果您需要传递对象本身,请在数据结构中的各个元素之后修改它们,而不必每次都检索它们,或者如果您使用自定义内存管理器来管理分配、释放和清理对象。

    将对象本身放入 STL 结构中更加容易和简单。它需要较少的 * 和 -> 运算符,您可能会发现这些运算符难以理解。某些 STL 对象需要对象本身而不是默认格式的指针(即需要散列条目的散列表 - 并且您想要散列对象,而不是指向它的指针),但您始终可以通过以下方式解决这个问题覆盖函数等。

    底线:在有意义的时候使用指针。否则使用对象。

    【讨论】:

    • 在这里使用指针仍然不是一个好主意。更好的是使用 STL 的迭代器并以这种方式迭代集合。如果您关心对象空间,最好使用某种形式的shared_ptr。最后,使用原始指针会破坏所有具有删除语义的标准算法,例如std::removestd::remove_ifstd::uniquestd::replacestd::replace_if 等。
    【解决方案5】:

    通常你使用对象。
    吃苹果比吃苹果棒(2米长的棒,因为我喜欢糖果苹果)更容易。

    在这种情况下,只需将其设为矢量

    如果你有一个 vector 这意味着你正在动态分配 g3Vector 的新对象(使用 new 运算符)。如果是这样,那么您需要在某些时候对这些指针调用 delete,而 std::Vector 并非旨在这样做。

    但每条规则都是例外。

    如果 g3Vector 是一个巨大的对象,复制成本很高(阅读您的文档很难说),那么将其存储为指针可能更有效。但在这种情况下,我会使用 boost::ptr_vector 因为它会自动管理对象的生命周期。

    【讨论】:

    • 对不起 - 该评论是为另一篇文章准备的。
    猜你喜欢
    • 2018-04-22
    • 2011-07-07
    • 2017-01-07
    • 1970-01-01
    • 1970-01-01
    • 2011-07-01
    • 1970-01-01
    • 2010-09-25
    相关资源
    最近更新 更多