关于c++:理解qt的qList以及函数传参

2次阅读

共计 9312 个字符,预计需要花费 24 分钟才能阅读完成。

数组四种类型

栈,堆

  qDebug() << "test_stack_heap start";

  Entity *entity1 = nullptr;
  Entity *const *p = nullptr;

  {
    MyList<Entity *> myList;

    entity1 = new Entity(1, "entity1");

    myList.push_back(entity1);

    qDebug() << "myList 地址:" << &myList
             << ", 数组指针变量地址:" << &myList.at(0)
             << ", 数组指针变量指向的内存地址:" << myList.at(0);

    // 1. 传值
    qDebug() << "funcParam";
    funcParam(myList);

    // 2. 传指针
    qDebug() << "funcParamPointer";
    funcParamPointer(&myList);

    // 3. 传援用
    qDebug() << "funcParamRef";
    funcParamRef(myList);

    p = &(myList.at(0));

    qDebug()<< (**p).id();  // myList 被删除前(函数体完结主动删除), 能够拜访到数组内元素地址, 进而取得堆内存里的 entity 内容

运行后果:

mylist 变量存于栈内存,Entity 指针变量存于栈内存 (数据量大的时候 QList 会存数据到堆内存),Entity 指针指向的 Entity 内容存于堆内存
生命周期完结后 mylist 开释,Entity 指针变量开释,Entity 指针指向的 Entity 内容不开释(需手动 delete)

传参:

  1. 传值
    将 mylist 的 Entity 指针变量拷贝复制到 list 里, 此时,list 与 mylist 地址不一样,list 的指针变量地址与 mylist 的指针变量地址不一样,list 的指针变量指向的内容与 mylist 的指针变量指向的内容一样
  2. 传指针
    将 mylist 的地址作为参数传递,此时只会有地址的拷贝,list 的地址与 mylist 的地址将会一样,指针变量的地址也一样,指针变量指向的内容地址也一样
  3. 传援用
    传援用与传指针一样

栈,栈

  qDebug() << "test_stack_stack start";
  Entity const *p = nullptr;
  {
    MyList<Entity> myList;
    Entity entity1(1, "entity1");
    myList.push_back(entity1);

    qDebug() << "myList 地址:" << &myList << ", 数组内容地址:" << &myList.at(0);

    // 1. 传值
    qDebug() << "funcParam";
    funcParam(myList);

    // 2. 传指针
    qDebug() << "funcParamPointer";
    funcParamPointer(&myList);

    // 3. 传援用
    qDebug() << "funcParamRef";
    funcParamRef(myList);

    p = &(myList.at(0));

    qDebug()<< (*p).id();  // myList 被删除前(函数体完结主动删除), 能够拜访到数组内元素, 取得数组存储的 entity 内容
  }

  qDebug() << (*p).id();  // 此时数组被开释,类指针被开释,无奈再通过其拜访

  qDebug() << "test_stack_stack end";

运行后果:

mylist 变量存于栈内存,Entity 内容存于栈内存(数据量大的时候 QList 会存数据到堆内存), 生命周期完结后 mylist 开释,Entity 内容开释

传参:

  1. 传值
    将 mylist 的 Entity 内容拷贝复制 (会拷贝两次, 一次是长期变量) 到 list 里, 此时,list 与 mylist 地址不一样,list 的内容地址与 mylist 的内容地址不一样
  2. 传指针
    将 mylist 的地址作为参数传递,此时只会有地址的拷贝,list 的地址与 mylist 的地址将会一样,内容地址也一样
  3. 传援用
    传援用与传指针一样

堆,栈

qDebug() << "test_heap_stack start";

  MyList<Entity> *myList = new MyList<Entity>;
  Entity const *p = nullptr;
  {Entity entity1(1, "entity1");
    myList->push_back(entity1);

    qDebug() << "myList 地址:" << myList << ", 数组内容地址:" << &myList->at(0);

    // 1. 传值
    qDebug() << "funcParam";
    funcParam(*myList);

    // 2. 传指针
    qDebug() << "funcParamPointer";
    funcParamPointer(myList);

    // 3. 传援用
    qDebug() << "funcParamRef";
    funcParamRef(*myList);

    p = &(myList->at(0));
  }
  qDebug() << (*p).id();  // 删除 myList 前, 能够拜访 entity 内容
  delete myList;
  qDebug() << (*p).id();  // 删除 myList 后, 无法访问 entity 内容

  qDebug() << "test_heap_stack end";

运行后果:

mylist 变量存于堆内存,Entity 内容存于栈内存(数据量大的时候 QList 会存数据到堆内存),mylist 需手动开释(开释后 Entity 内容则主动开释)

传参:

  1. 传值
    将 mylist 的 Entity 内容拷贝复制 (会拷贝两次, 一次是长期变量) 到 list 里, 此时,list 与 mylist 地址不一样,list 的内容地址与 mylist 的内容地址不一样
  2. 传指针
    将 mylist 指针变量作为参数传递,此时只会有地址的拷贝,list 的地址与 mylist 的地址将会一样,内容地址也一样
  3. 传援用
    传援用与传指针一样

堆,堆

qDebug() << "test_heap_heap start";

  MyList<Entity *> *myList = new MyList<Entity *>;
  Entity *entity1 = nullptr;
  Entity *const *p = nullptr;
  {entity1 = new Entity(1, "entity1");
    myList->push_back(entity1);

    qDebug() << "myList 地址:" << myList
             << ", 数组指针变量地址:" << &myList->at(0)
             << ", 数组指针变量指向的内存地址:" << myList->at(0);

    // 1. 传值
    qDebug() << "funcParam";
    funcParam(*myList);

    // 2. 传指针
    qDebug() << "funcParamPointer";
    funcParamPointer(myList);

    // 3. 传援用
    qDebug() << "funcParamRef";
    funcParamRef(*myList);

    p = &(myList->at(0));
  }
  qDebug() << (**p).id();  // "删除 myList 前, 能够拜访 entity 内容"
  delete myList;
  //  qDebug() <<  (**p).id(); //"删除 myList 后, 无法访问 entity 内容"
  qDebug() << entity1->id();  // 堆内存 Entity 内容仍然存在
  delete entity1;
  qDebug() << "test_heap_heap end";

运行后果:

mylist 变量存于堆内存,Entity 指针变量存于栈内存(数据量大的时候 QList 会存数据到堆内存),Entity 指针指向的 Entity 内容存于堆内存,mylist 需手动开释(开释后 Entity 指针变量开释, 如果 Entity 指针指向的 Entity 内容不手动开释,则可能造成内存透露),Entity 内容需手动开释

传参:

  1. 传值
    将 mylist 的 Entity 指针变量拷贝复制到 list 里, 此时,list 与 mylist 地址不一样,list 的指针变量地址与 mylist 的指针变量地址不一样,list 的指针变量指向的内容与 mylist 的指针变量指向的内容一样
  2. 传指针
    将 mylist 指针变量作为参数传递,此时只会有地址的拷贝,list 的地址与 mylist 的地址将会一样,list 的指针变量地址与 mylist 的指针变量地址一样,list 的指针变量指向的内容与 mylist 的指针变量指向的内容一样
  3. 传援用
    传援用与传指针一样

最初附上代码:

entity

//entity.h
#ifndef ENTITY_H
#define ENTITY_H

#include <QDebug>
#include <QString>

class Entity {
 public:
  Entity();
  Entity(int id, QString name);
  Entity(const Entity& entity);
  Entity& operator=(const Entity& entity);
  ~Entity();

  int id() const;
  void setId(int newId);

  const QString& name() const;
  void setName(const QString& newName);

  void sayHello(QString text);

 private:
  int m_id;
  QString m_name;
};

#endif  // ENTITY_H

//entity.cpp
#include "entity.h"

#include <QDebug>

Entity::Entity() {//    qDebug() << "Entity construtor";
}

Entity::Entity(int id, QString name) {
  this->m_id = id;
  this->m_name = name;
  //  qDebug() << "Entity construtor" << m_id << m_name;}

Entity::Entity(const Entity &entity) {
  this->m_id = entity.m_id;
  this->m_name = entity.m_name;
  //  qDebug() << "Entity copy" << m_id << m_name;}

Entity &Entity::operator=(const Entity &entity) {if (this != &entity) {
    this->m_id = entity.m_id;
    this->m_name = entity.m_name;
  }
  //  qDebug() << "Entity =" << m_id << m_name;
  return *this;
}

Entity::~Entity() {//    qDebug() << "Entity delete" << m_id << m_name;
}

int Entity::id() const { return m_id;}

void Entity::setId(int newId) {m_id = newId;}

const QString &Entity::name() const { return m_name;}

void Entity::setName(const QString &newName) {m_name = newName;}

void Entity::sayHello(QString text) {qDebug() << "Entity SayHello!" << text; }

mylist

//mylist.h
#ifndef MYLIST_H
#define MYLIST_H

#include <QDebug>
#include <QList>

#include "entity.h"

template <typename T>
class MyList : public QList<T> {
 public:
  MyList();
  MyList(MyList *myList) {for (int i = 0; i < myList->length(); i++) {this->push_back(myList->at(i));
    }
  }
  MyList(MyList &myList) {for (int i = 0; i < myList.length(); i++) {this->push_back(myList.at(i));
    }
  }

  ~MyList();};

template <typename T>
MyList<T>::MyList() : QList<T>() {//  qDebug() << "MyList constrotor";
}

template <typename T>
MyList<T>::~MyList() {//  qDebug() << "MyList delete";
}

#endif  // MYLIST_H

mainwindow

//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include "entity.h"
#include "mylist.h"

QT_BEGIN_NAMESPACE
namespace Ui {class MainWindow;}
QT_END_NAMESPACE

class MainWindow : public QMainWindow {
  Q_OBJECT

 public:
  MainWindow(QWidget *parent = nullptr);
  ~MainWindow();

  void test_stack_heap();
  void test_stack_stack();
  void test_heap_stack();
  void test_heap_heap();
  void test_funcParam();

  void funcParam(MyList<Entity> list);
  void funcParamPointer(MyList<Entity> *list);
  void funcParamRef(MyList<Entity> &list);
  void funcParam(MyList<Entity *> list);
  void funcParamPointer(MyList<Entity *> *list);
  void funcParamRef(MyList<Entity *> &list);

 private:
  Ui::MainWindow *ui;
};
#endif  // MAINWINDOW_H

//mainwindow.cpp
#include "mainwindow.h"

#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);

  //  test_stack_heap();  // 栈 - 堆
  //  test_stack_stack();  // 栈 - 栈
  //  test_heap_stack();  // 堆 - 栈
  test_heap_heap();  // 堆 - 堆}

MainWindow::~MainWindow() { delete ui;}

void MainWindow::test_stack_heap() {qDebug() << "test_stack_heap start";

  Entity *entity1 = nullptr;
  Entity *const *p = nullptr;

  {
    MyList<Entity *> myList;

    entity1 = new Entity(1, "entity1");

    myList.push_back(entity1);

    qDebug() << "myList 地址:" << &myList
             << ", 数组指针变量地址:" << &myList.at(0)
             << ", 数组指针变量指向的内存地址:" << myList.at(0);

    // 1. 传值
    qDebug() << "funcParam";
    funcParam(myList);

    // 2. 传指针
    qDebug() << "funcParamPointer";
    funcParamPointer(&myList);

    // 3. 传援用
    qDebug() << "funcParamRef";
    funcParamRef(myList);

    p = &(myList.at(0));

    qDebug()
        << (**p)
               .id();  // myList 被删除前(函数体完结主动删除), 能够拜访到数组内元素地址, 进而取得堆内存里的 entity 内容
  }

  // qDebug()
  // <<(**p).id();// 此时数组被开释,类指针被开释,无奈再通过其拜访堆内存内容
  qDebug() << entity1->id();  // 堆内存 Entity 内容仍然存在

  delete entity1;

  qDebug() << "test_stack_heap end";}

void MainWindow::test_stack_stack() {qDebug() << "test_stack_stack start";
  Entity const *p = nullptr;
  {
    MyList<Entity> myList;
    Entity entity1(1, "entity1");
    myList.push_back(entity1);

    qDebug() << "myList 地址:" << &myList << ", 数组内容地址:" << &myList.at(0);

    // 1. 传值
    qDebug() << "funcParam";
    funcParam(myList);

    // 2. 传指针
    qDebug() << "funcParamPointer";
    funcParamPointer(&myList);

    // 3. 传援用
    qDebug() << "funcParamRef";
    funcParamRef(myList);

    p = &(myList.at(0));

    qDebug()
        << (*p).id();  // myList 被删除前(函数体完结主动删除), 能够拜访到数组内元素, 取得数组存储的 entity 内容
  }

  qDebug() << (*p).id();  // 此时数组被开释,类指针被开释,无奈再通过其拜访

  qDebug() << "test_stack_stack end";}

void MainWindow::test_heap_stack() {qDebug() << "test_heap_stack start";

  MyList<Entity> *myList = new MyList<Entity>;
  Entity const *p = nullptr;
  {Entity entity1(1, "entity1");
    myList->push_back(entity1);

    qDebug() << "myList 地址:" << myList << ", 数组内容地址:" << &myList->at(0);

    // 1. 传值
    qDebug() << "funcParam";
    funcParam(*myList);

    // 2. 传指针
    qDebug() << "funcParamPointer";
    funcParamPointer(myList);

    // 3. 传援用
    qDebug() << "funcParamRef";
    funcParamRef(*myList);

    p = &(myList->at(0));
  }
  qDebug() << (*p).id();  // 删除 myList 前, 能够拜访 entity 内容
  delete myList;
  qDebug() << (*p).id();  // 删除 myList 后, 无法访问 entity 内容

  qDebug() << "test_heap_stack end";}

void MainWindow::test_heap_heap() {qDebug() << "test_heap_heap start";

  MyList<Entity *> *myList = new MyList<Entity *>;
  Entity *entity1 = nullptr;
  Entity *const *p = nullptr;
  {entity1 = new Entity(1, "entity1");
    myList->push_back(entity1);

    qDebug() << "myList 地址:" << myList
             << ", 数组指针变量地址:" << &myList->at(0)
             << ", 数组指针变量指向的内存地址:" << myList->at(0);

    // 1. 传值
    qDebug() << "funcParam";
    funcParam(*myList);

    // 2. 传指针
    qDebug() << "funcParamPointer";
    funcParamPointer(myList);

    // 3. 传援用
    qDebug() << "funcParamRef";
    funcParamRef(*myList);

    p = &(myList->at(0));
  }
  qDebug() << (**p).id();  // "删除 myList 前, 能够拜访 entity 内容"
  delete myList;
  //  qDebug() <<  (**p).id(); //"删除 myList 后, 无法访问 entity 内容"
  qDebug() << entity1->id();  // 堆内存 Entity 内容仍然存在
  delete entity1;
  qDebug() << "test_heap_heap end";}

void MainWindow::funcParam(MyList<Entity> list) {qDebug() << "list 地址:" << &list << ", 数组内容地址:" << &list.at(0);
}

void MainWindow::funcParamPointer(MyList<Entity> *list) {qDebug() << "list 地址:" << list << ", 数组内容地址:" << &list->at(0);
}

void MainWindow::funcParamRef(MyList<Entity> &list) {qDebug() << "list 地址:" << &list << ", 数组内容地址:" << &list.at(0);
}

void MainWindow::funcParam(MyList<Entity *> list) {qDebug() << "list 地址:" << &list << ", 数组指针变量地址:" << &list.at(0)
           << ", 数组指针变量指向的内存地址:" << list.at(0);
}

void MainWindow::funcParamPointer(MyList<Entity *> *list) {qDebug() << "list 地址:" << list << ", 数组指针变量地址:" << &list->at(0)
           << ", 数组指针变量指向的内存地址:" << list->at(0);
}

void MainWindow::funcParamRef(MyList<Entity *> &list) {qDebug() << "list 地址:" << &list << ", 数组指针变量地址:" << &list.at(0)
           << ", 数组指针变量指向的内存地址:" << list.at(0);
}
正文完
 0