簡體   English   中英

C ++指針和類成員變量混淆

[英]C++ pointers and class member variables confusion

我想知道類成員(屬性)的生命周期是什么。

目前我有這個班:

class Snake {

private:
    std::vector<Position> positions = std::vector<Position>();

public:
    void addNode(Position * position);
};

我不確定addNode函數是否必須接收指針或對象? 我的猜測是,如果addNode收到一個Position位置作為參數,那么一旦它超出創建的范圍,對象就會死掉,例如

... code here ...
{
Position p = Position(..);
snake.addNode(p);
}
// p should die over here so it could cause a null pointer on the program

另一方面,如果addNode收到一個指針,那么p不會死掉,除非我刪除它(因此它不會導致任何nullpointer),也許你們可以幫助我澄清這個關於我現在的指針的巨大混亂,

謝謝。

對象不需要是指針,但指針是對象。 指針只是一個對象,它存儲一個數字作為某個對象的內存地址。 當指針超出范圍而不會刪除它指向(因此內存泄漏)的對象。

如果您希望您的代碼是最高效和正確的,您應該:

  1. 使用const引用而不是指針。
  2. 提供您的功能的移動版本。

如下所示,這將是代碼:

void addNode(const Position& position)
{
    positions.push_back(position);
}
void addNode(Position&& position)
{
    positions.push_back(std::move(position));
}

它允許避免制作冗余副本並使用const Position作為參數。 這種方式比其他answears( void addNode(Position position) )中建議的方式更快,因為它避免了參數的復制到函數中。

當您知道它將超出范圍時,另一個優化是將位置移動到該函數:

{
    Position p = Position(x, y);
    snake.addNode(std::move(p)); //mind the std::move
} //p will go out of scope here anyway, so it can safely be moved

我們假設addNode有實現

addNode(Position p){
    positions.push_back(p);
}

輸入變量是您傳入的變量的副本。一旦在向量上調用push_back,另一個副本就會在向量內創建,並在向量被銷毀時被銷毀。 此p將被銷毀,但這沒有任何影響,因為vector包含一個副本。 通常,如果編譯器是智能的,它可以避免一些副本,並且可以使用例如std :: move來改進代碼,但我不想為答案添加太多復雜性。

你對“空指針”的評論有點不精確:如果你有一個指針向量,你可以在向量中插入指向p的指針。 如果p超出范圍,指針將懸空,使程序的行為不確定。

不要使用指針,明顯有什么問題?

public:
    void addNode(Position position);

問題的關鍵是,雖然position參數將一次函數退出死了,它的值復制到載體中,並將復印生活在載體,即使原來已經死亡。

這里真的沒有必要指點。

類成員的生命周期與實例相關聯。 它的生命始於構造函數的初始化列表,並在析構函數調用結束時結束。

您似乎認為類是參考值 - 使用C#術語 - 它們不是。 所有C ++對象都是值類型:

  • {Position p;...}Position類型的對象。 它的構造函數在塊的開頭創建對象,並在結束時調用它的析構函數,這會破壞其內容和對象本身。
  • {Position* ptr{&p};...}Position*類型的對象。 它的“構造函數”初始化指針。 它的析構函數是無操作但如果它存在則會簡單地破壞它的value = address = number而不是它指向的對象。 指針是另一個對象的地址,在塊的末尾,無論內容是什么,指針都會被銷毀。 就像{int i = 0;}會破壞i ,而不是0

  • {Position& ptr{p};...}與指針相同的規則。 銷毀引用,而不是引用的對象。

核心思想是指針只是另一種普通的值類型:

Position p;
//Introduces a new name for a type
using Position_p = Position*;

Position_p p1 = &p;
Position_p p2 = p1;
p2++; // Change p2
//p1 is still the same.
int i1 = 5;
int i2 = i1;
i2++; // Change i2
//i1 is still the same.

它們看起來一樣,甚至副本的行為都應該如此。 就像i2獲得了i1內容一樣, p2獲得了p1內容。 對於int ,內容是一個數字,對於Position_p它是一個地址。 如果您理解這個概念,那么指針應該變得非常直觀。

所以我的猜測是你想擁有std::vector<Position>addNode(Position p) 但這會產生不必要的副本,因此addnode(const Position& p)更好。 你可以在里面做push_back ,並將值復制到向量中。 如果需要,可以使用移動語義來刪除最后一個副本。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM