C ++ DoublyLinkedList单元测试因智能初始化而失败,但通过新的

时间:2016-07-20 12:11:10

标签: c++ unit-testing googletest

我正在使用C ++编写DoublyLinkedList编程,我为此实现编写的其中一个测试以一种奇怪的方式失败。

我创建了一个StubClass来填充我的DoublyLinkedList,其定义如下:

class StubClass {
public:
  int data;

  StubClass(int _data) {
    data = _data;
  }

  StubClass() {
    data = -1;
  }
};

我正在使用Google Test for C ++。我有以下装置:

class DoublyLinkedListTest : public ::testing::Test {
public:
  DoublyLinkedList<StubClass> doublyLinkedList;
};

通过以下测试:

TEST_F(DoublyLinkedListTest, LargePushAndPopRoutineWithSmartInitializedData) {
  int repetitions = 12;
  for (int i = 0; i < repetitions; i++) {
    StubClass stub(i);
    doublyLinkedList.push_back(&stub);
  }

  for (int i = 0; i < repetitions; i++) {
    ASSERT_EQ(i, doublyLinkedList.pop_front()->data);
  }
}

问题是StubClass对象中的所有DoublyLinkedList对象都将其数据字段设置为11.因此测试失败,因为从前面弹出的第一个项目应该设置其数据字段测试运行的输出:

Value of: doublyLinkedList.pop_front()->data
  Actual: 11
Expected: i
Which is: 0

奇怪的是,以下测试确实通过了:

TEST_F(DoublyLinkedListTest, LargePushAndPopRoutine) {
  int repetitions = 12;
  for (int i = 0; i < repetitions; i++) {
    doublyLinkedList.push_back(new StubClass(i));
  }

  for (int i = 0; i < repetitions; i++) {
    ASSERT_EQ(i, doublyLinkedList.pop_front()->data);
  }
}

此测试使用new关键字来实例化StubClass,而不是失败测试中的智能初始化。

我对C ++没有多少经验,只是学习复制和移动构造函数。我怀疑在失败的测试中我可能犯了一个愚蠢的C ++初学者错误。

为了完整起见,我将在下面列出DoublyLinkedList类的实现:

DoublyLinkedList.h

#ifndef PROJECT_DOUBLYLINKEDLIST_H
#define PROJECT_DOUBLYLINKEDLIST_H

#include "DoublyLinkedNode.h"

template<class T>
class DoublyLinkedList {
private:
  DoublyLinkedNode<T> *head = nullptr;
  DoublyLinkedNode<T> *tail = nullptr;

public:
  bool hasOneItem() {
    return head == tail && !isEmpty();
  }

  void push_front(T* data) {
    DoublyLinkedNode <T> *newNode = new DoublyLinkedNode<T>();
    newNode->data = data;

    if (isEmpty()) {
      head = newNode;
      tail = newNode;
    }
    else {
      newNode->setNext(head);
      head = newNode;
    }
  }

  void push_back(T* data) {
    DoublyLinkedNode <T> *newNode = new DoublyLinkedNode<T>();
    newNode->data = data;

    if (isEmpty()) {
      head = newNode;
      tail = newNode;
    }
    else {
      newNode->setPrev(tail);
      tail = newNode;
    }
  }

  T* pop_front() {
    if (isEmpty()) {
      return nullptr;
    }

    DoublyLinkedNode<T> *oldHead = head;
    if (hasOneItem()) {
      head = nullptr;
      tail = nullptr;

      return oldHead->data;
    }

    head->next->prev = nullptr;
    head = head->next;

    return oldHead->data;
  }

  T* pop_back() {
    if (isEmpty()) {
      return nullptr;
    }

    DoublyLinkedNode<T> *oldTail = tail;
    if (hasOneItem()) {
      head = nullptr;
      tail = nullptr;

      return oldTail->data;
    }

    tail->prev->next = nullptr;
    tail = tail->prev;

    return oldTail->data;
  }

  bool isEmpty() {
    return !head && !tail;
  }
};

#endif //PROJECT_DOUBLYLINKEDLIST_H

DoublyLinkedNode.h

#ifndef PROJECT_DOUBLYLINKEDNODE_H
#define PROJECT_DOUBLYLINKEDNODE_H

template<class T>
class DoublyLinkedNode {
public:
  DoublyLinkedNode *prev = nullptr;
  DoublyLinkedNode *next = nullptr;
  T *data = nullptr;

  /**
   * Will also set 'prev' on the nextNode
   */
  void setNext(DoublyLinkedNode *nextNode) {
    next = nextNode;

    if (nextNode) {
      nextNode->prev = this;
    }
  }

  void setPrev(DoublyLinkedNode *prevNode) {
    prevNode->setNext(this);
  }
};

#endif //PROJECT_DOUBLYLINKEDNODE_H

1 个答案:

答案 0 :(得分:4)

这是因为您正在创建for循环的本地对象,然后使用这些对象的地址将它们推送到列表中。在相应的循环迭代终止后,这些对象中的每一个都被销毁。在您的情况下,它们都是在堆栈上的相同地址创建的,这就是为什么看起来它们都被初始化为数据字段设置为11.实际上,您的列表包含指向用于创建这些内容的相同内存位置的指针对象,写入此位置的最后一件事是数据字段设置为11的对象。

但是,当您使用new时,这些对象将在堆上分配到不同的位置。这就是为什么一切都按预期工作的原因。在这种情况下,您有内存泄漏,因为您的容器不会删除这些对象。