C++ - 在不使用节点构造函数的情况下插入链表。可能吗?

C++ - Insertion in a Linked List without using a node's constructor. Is it possible?

我正致力于在 C++ 中实现一个模板化链表,该链表将用于模拟火车穿过许多停靠站,其中添加和删除了火车车厢。 Traincar 是它自己的 class,每个对象都应该被赋予一个从 1 开始的唯一 ID,并在添加汽车时递增。但是,当 运行 我的代码时,id 的增量超出了预期。

经过一些实验并在先前答案的帮助下,我确定是 LinkedList class 方法中的 new node 语句导致 id 增加得更多比想要的。但是,我没有看到在不创建 new node 的情况下实现 insertion 方法的方法。有什么解决办法吗?

这是我的 TrainCar class:

class TrainCar {
public:
  static int nextID;
  int id;
  char typeOfCar;
  int numberOfStops;
  node<char>* car;

  TrainCar();
};

int TrainCar::nextID = 1;

TrainCar::TrainCar() {
  cout << "id++" << endl;
  id = nextID++;
  int i = (rand() % 3);//gives a random number 0 - 2, used to determine what
                       //type of car to add
  if(i == 0) {
    typeOfCar = 'P';
  }
  else if(i == 1) {
    typeOfCar = 'C';
  }
  else {
    typeOfCar = 'M';
  }
  car = new node<char>(typeOfCar);
  numberOfStops = (rand() % 5) + 1;//gives a random number 1 - 5;
}

这是我的 main() 函数

int main() {
  LinkedList<TrainCar> train;
  int addCargoCar = 0;

  for(int i = 0; i < 10; i++) {
    TrainCar newCar;
    if(newCar.typeOfCar == 'P') {
      train.AddToFront(newCar);
      addCargoCar++;
    }
    else if(newCar.typeOfCar == 'C') {
      train.AddAtIndex(newCar, addCargoCar);
    }
    else {
      train.AddToEnd(newCar);
    }
  }

  cout <<"Welcome to the Train Station! Here is your train!" << endl;
  char type;
  int id, numberOfStops, i, j;
  for(i = 0; i < train.size; i++) {
    type = train.Retrieve(i).typeOfCar;
    id = train.Retrieve(i).id;
    numberOfStops = train.Retrieve(i).numberOfStops;
    cout << "[" << id << ":" << type << ":" << numberOfStops << "] ";
  }
}

输出应该类似于

[5:P:1][6:P:4][8:P:2][3:P:2][10:C:3][2:C:3][4:C:1][1:M:1][7:M:3][9:M:2]

但我的输出是:

[17:P:2][9:P:2][5:C:2][19:C:1][15:C:2][1:M:5][3:M:4][7:M:1][11:M:3][13:M:1]

编辑:这是 AddToFront() 方法:(所有其他添加方法在本质上都是相似的)。输出的问题是 new node<T>(d) 语句

template <class T>
void LinkedList<T>::AddToFront(T d) {
  node<T>* newNode = new node<T>(d);

  if(head == NULL) {
    head = newNode;
    tail = newNode;
    size++;
  }

  else {
    newNode->next = head;
    head = newNode;
    size++;
  }
}

Edit2:这是我的检索函数(现已修复,不再使用 new node 语句):

template <class T>
T LinkedList<T>::Retrieve(int index) {
  node<T>* cur = head;
  for(int i = 0; i < index; i++) {
    cur = cur->next;
  }
  return(cur->data);
}

您使用 static 成员变量来跟踪标识符的想法是正确的。 但是你不能那个。

static 成员变量是 class 的成员,而不是任何特定对象。因此所有对象共享相同的 id.

使用一个静态成员来跟踪下一个可能的id,然后使用一个non-static成员变量来存储对象的实际 ID。

类似

class TrainCar {
public:
    static int next_id;  // Used to get the id for the next object
    int id;  // The objects own id
    ...
};

TrainCar::TrainCar() {
    id = next_id++;  // Get next id and save it
    ...
}

您可能还应该有一个复制构造函数和复制赋值运算符,否则您可能会得到两个具有相同 ID 的对象。


关于

Why are the id values so high and why are they being incremented by more than one each time?

那是因为您创建的对象可能比您预期的要多。使用您显示的代码以及上面建议的更改,您将为每个默认构造的对象创建一个新的 id。根据您的 LinkedList 模板 class 正在做什么(您为什么不使用 std::vector),可能会创建新对象。

一个有根据的猜测是你的列表 class 的 Retreive 函数默认构造它包含的对象。这就是为什么你在打印时得到三个对象的原因,因为你调用 Retrieve 三次。可能与您的 Add 函数有类似的故事。