理解qt的qList,以及函数传参

2年前 (2022) 程序员胖胖胖虎阿
380 0 0

数组四种类型

栈,堆

  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内容

运行结果:
理解qt的qList,以及函数传参

mylist变量存于栈内存,Entity指针变量存于栈内存,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";

运行结果:
理解qt的qList,以及函数传参

mylist变量存于栈内存,Entity内容存于栈内存,生命周期结束后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";

运行结果:
理解qt的qList,以及函数传参

mylist变量存于堆内存,Entity内容存于堆内存,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";

运行结果:
理解qt的qList,以及函数传参

mylist变量存于堆内存,Entity指针变量于堆内存,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);
}
版权声明:程序员胖胖胖虎阿 发表于 2022年9月24日 下午4:40。
转载请注明:理解qt的qList,以及函数传参 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...