c++ 查询不意味着是复制的,请改用移动构造

hxzsmxv2  于 2023-02-17  发布在  其他
关注(0)|答案(2)|浏览(131)

我一直在做一个代码,其中数据库被操纵,元素被保存和编辑的Qsqlite数据库和查询,所以我一直使用的方式是通过参数传递查询我不知道它有多糟糕,但每次它通过参数我得到这个警告:“不推荐使用QSqlQuery:并不意味着可以复制:使用移动构造代替”,我想知道正确的方法,我显示了MainWindow构造函数,(警告在main中指出)。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{   

    ui->setupUi(this);
    char dirNow[1024];

    db = QSqlDatabase::addDatabase("QSQLITE");
    QString dirfull = QString(_getcwd(dirNow, 1024)) + "\\inventario.db";
    db.setDatabaseName(dirfull);

    if(!db.open()){
        qDebug() << db.lastError().text();
    }

    model = new QSqlQueryModel();

    QSqlQuery query(db);


    if(!query.exec("CREATE TABLE IF NOT EXISTS articulo (codigo INTEGER NOT NULL, nombre VARCHAR(55) NOT NULL, unidades INTEGER NOT NULL, "
                   "categoria VARCHAR(55) NOT NULL, pais VARCHAR(55) NOT NULL, precio DOUBLE NOT NULL, foto VARCHAR(200) NOT NULL, id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT) ")){
            QMessageBox::information(this, "Error", query.lastError().text());
    }

    if(!query.exec("CREATE TABLE IF NOT EXISTS categorias(valor VARCHAR(55) NOT NULL) ")){
        QMessageBox::information(this, "Error", query.lastError().text());
    }

    //query.prepare("DELETE FROM articulo WHERE  = 1");
    //query.addBindValue("");

    "Warning is here: " id = imprimirArticulos(query);

    "Warning is here: " QObject::connect(ui->registrarBtn, &QPushButton::clicked, this, [=]()->void{registrarArticulo(query); });
    QObject::connect(ui->addImagenBtn, &QPushButton::clicked, this, [=]()->void{subirFoto();});
    "Warning is here: " QObject::connect(ui->buscarBtn, &QPushButton::clicked, this, [=]()->void{filtroArticulos(query);});

    "Warning is here: " imprimirCategorias(query);
    "Warning is here: " QObject::connect(ui->categoriasCBox, &QComboBox::currentIndexChanged, this, [=]()->void{agregarCategorias(query);});

    model->setQuery(std::move(query));
}
0g0grzrc

0g0grzrc1#

他们只想移动QSqlQuery对象,这样就只存在一个查询。

id = imprimirArticulos(query) //creates copy of query

您需要做的是移动query

id = imprimirArticulos(std::move(query))

如果你在移动后再次尝试使用query,它将是未定义的行为,所以你必须将它从function移回main,以便在imprimirCategorias中再次使用它。

2guxujil

2guxujil2#

对fg的回答进行了扩展并编辑了:当你调用一个传递query对象的函数时,编译器会复制它(就像它对任何堆栈分配对象所做的那样)。复制的确切类型通常取决于类的 * 复制构造函数 *。对于此类,它似乎是一个浅复制。因此,当query对象具有关联的资源时(例如,当你 * 准备 * 查询和与之关联的绑定变量时),所有的示例(原始的和每个函数使用的副本)将指向相同的“内部”资源,当(且仅当)你改变query的一个示例中的某些内容,影响其他示例时,这可能会导致问题。
这并不完全是同一个案例,但你可以在这里读到:https://doc.qt.io/qt-6/qsqlquery-obsolete.html
无法有意义地复制QSqlQuery。根据数据库驱动程序的不同,预准备语句、绑定值等将无法正常工作(例如,更改副本将影响原始副本)。请将QSqlQuery视为仅移动类型。
当使用std::move(query)时,您获得query的“xvalue表达式”,它可以直接传递给一些库重载。这些重载实际上是 *move构造函数 *(并且因为它们 “可能假定自变量是对对象的唯一引用”,所以它们将很可能“窃取”对象的内容,使query处于“未定义行为”状态,调用函数不再可用)。请参见:https://en.cppreference.com/w/cpp/utility/move
这里的关键点是:如果query对象未被修改(在主代码或被调用函数中),您可以:a)撤销警告并保持代码不变;或者B)使用std::move()并为每次调用创建一个新的query对象。在调用std::move()之后,您不能(不应该)重用原来的query。相反,如果您确实修改了query对象(可能在其中一个函数内部),您唯一的选择就是创建单独的示例。

相关问题