Los cambios en Qt Core
Qt 6 son el resultado del esfuerzo consciente por hacer el framework más eficiente y fácil de usar.
Intentamos mantener la compatibilidad binaria y de código fuente de todas las API públicas en cada versión. Pero algunos cambios eran inevitables en un esfuerzo por hacer de Qt un framework mejor.
En este tema resumimos esos cambios en Qt Core, y proporcionamos una guía para manejarlos.
Clases contenedoras
QHash, QMultiHash, QSet
Firma qHash()
Para tipos personalizados, QHash y QMultiHash dependen de que proporciones un custom qHash() function en el mismo espacio de nombres. En Qt 4 y Qt 5, el valor de retorno y el segundo argumento opcional de una función qHash eran de tipo uint. En Qt 6, es size_t.
Es decir, hay que cambiar
por
size_t qHash(MyType x, size_t seed);
Esto permite que QHash, QMultiHash y QSet contengan más de 2^32 elementos en plataformas de 64 bits.
Estabilidad de las referencias
La implementación de QHash, QMultiHash y QSet en Qt 6 ha cambiado de un enfoque basado en nodos a una tabla de búsqueda de dos etapas. Este diseño permite mantener la sobrecarga de memoria de una instancia hash muy pequeña, mientras que al mismo tiempo proporciona un buen rendimiento.
Un cambio de comportamiento a tener en cuenta es que la nueva implementación no proporcionará referencias estables a los elementos del hash cuando la tabla necesite crecer, o cuando se eliminen entradas. Las aplicaciones que dependan de dicha estabilidad podrían ahora encontrarse con un comportamiento indefinido.
Eliminación de QHash::insertMulti
En Qt 5, QHash podía usarse para crear hashes multivaluados usando QHash::insertMulti, y QMultiHash derivaba de QHash.
En Qt 6, ambos tipos y casos de uso son distintos, y QHash::insertMulti fue eliminado.
QVector, QList
Antes de Qt 6, QVector y QList eran clases separadas. En Qt 6, están unificadas: La implementación de QList en Qt 5 ha desaparecido y ambas clases usan en su lugar la implementación actualizada de QVector. QList es la clase con la implementación actual y QVector es un alias (typedef) de QList.
QListEn Qt 6, las funciones fromVector() y toVector() de Qt 5 y fromList() y toList() de QVector ya no implican la copia de datos. Ahora devuelven el objeto para el que fueron llamadas.
Cambios en la API
QListEl tipo de tamaño de QVector(y por tanto de ) cambia de int a qsizetype. Junto con el tipo de tamaño, todas las firmas de los métodos relevantes se actualizan para utilizar qsizetype. Esto permite que QList contenga más de 2^31 elementos en plataformas de 64 bits.
Al actualizar la base de código a Qt 6, este cambio en la API probablemente daría lugar a advertencias del compilador sobre conversiones de tipo estrechas. Teniendo el siguiente código de ejemplo:
void myFunction(QList<MyType> &data) { int size = data.size(); // ... const int pos = getInsertPosition(size); data.insert(pos, MyType()); // ... }
necesitaría actualizarlo para usar qsizetype o una palabra clave auto:
void myFunction(QList<MyType> &data) { auto size = data.size(); // ... const auto pos = getInsertPosition(size); data.insert(pos, MyType()); // ... }
Alternativamente, puede utilizar la conversión de tipos y convertir todo a int o a qsizetype.
Nota: Si quieres compilar contra Qt 5 y Qt 6, la palabra clave auto es una buena solución para cubrir las diferencias de firmas entre las versiones.
Disposición de la memoria
QList recibió múltiples cambios relacionados con la disposición de la memoria en Qt 6.
En Qt 5, sizeof(QList<T>) era igual al tamaño de un puntero. Ahora, la indirección extra del puntero se elimina y los miembros de datos de QList se almacenan directamente en el objeto. Por defecto, se espera que sizeof(QList<T>) sea igual al tamaño de 3 punteros.
Al mismo tiempo, también se actualiza la disposición de memoria de los elementos. QList ahora siempre almacena sus elementos directamente en la región de memoria asignada, a diferencia de Qt 5, donde ciertos objetos se asignaban por separado en el montón y los punteros a los objetos se colocaban en cambio en QList.
Nótese que esto último, en particular, afecta a los objetos grandes. Para tener el comportamiento de Qt 5, podrías envolver tus objetos en punteros inteligentes y almacenar estos punteros inteligentes en QList directamente. En este caso, el tipo de su QList sería QList<MySmartPointer<MyLargeObject>> en lugar de QList<MyLargeObject> en Qt 5.
Estabilidad de las referencias
Se han realizado varios cambios en la implementación de QVector/QList. El relacionado con QVector es: se optimiza la inserción al principio (de forma similar a QList en Qt 5). El relacionado con QList es: se simplifica la disposición de memoria para los elementos.
Importante: Estos cambios afectan a la estabilidad de las referencias. En Qt 6, debes considerar que cualquier método que modifique el tamaño o la capacidad invalida todas las referencias, incluso cuando QList no esté implícitamente compartido. Las excepciones a esta regla se documentan explícitamente.
Las aplicaciones que dependen de cierta estabilidad de referencias podrían encontrarse con comportamientos indefinidos cuando se actualicen para usar Qt 6. Deberías prestar especial atención a los casos en los que QVector o QList con un diseño de array no compatible con C fueron usados originalmente.
Ver clases en Qt6
Visión general
Hay varias clases View nuevas que vienen con Qt6. Está la ya existente QStringView, ahora acompañada por QByteArrayView y seguida por una especializada QUtf8StringView y una más universal QAnyStringView.
Introducción a las clases view con el ejemplo de QStringView
La clase QStringView proporciona una vista unificada sobre cadenas UTF-16 con un subconjunto de sólo lectura de la API QString. A diferencia de QString, que mantiene su propia copia de la cadena (posiblemente ref-contada), QStringView proporciona una vista de una cadena que está almacenada en otro lugar.
char hello[]{ "Hello." }; // narrow multi-byte string literal QString str{hello}; // needs to make a copy of the string literal QString strToStr(str); // atomic increment involved to not create a copy of hello again // The above code can be re-written to avoid copying and atomic increment. QStringView view{ u"Hello." }; // view to UTF-16 encoded string literal QStringView viewToView{ view }; // view of the same UTF-16 encoded string literal
La cadena "Hello." se almacena en el binario y no se asigna en tiempo de ejecución. view es sólo una vista de la cadena "Hello.", por lo que no es necesario crear ninguna copia. Cuando copiamos un QStringView, el viewToView observa la misma cadena que está observando el view copiado. Esto significa que viewToView no necesita crear una copia o un incremento atómico. Son vistas sobre la cadena existente "Hello.".
Vistas como argumento de función
Las vistas deben pasarse por valor, no por referencia-a-const.
void myfun1(QStringView sv); // preferred void myfun2(const QStringView &sv); // compiles and works, but slower
Funciones de manipulación de vistas
QStringView soporta funciones que nos permiten manipular la vista de la cadena. Esto nos permite cambiar la vista sin crear una copia parcial de la cadena vista.
QString pineapple = "Pineapple"; QString pine = pineapple.left(4); // The above code can be re-written to avoid creating a partial copy. QStringView pineappleView{ pineapple }; QStringView pineView = pineappleView.left(4);
Cadenas sin terminación nula y cadenas que contienen '\0'
QStringView admite tanto cadenas terminadas en cero como cadenas no terminadas en cero. La diferencia radica en la forma de inicializar QStringView:
QChar aToE[]{ 'a', 'b', 'c', 'd', 'e' }; QStringView nonNull{ aToE, std::size(aToE) }; // with length given QStringView nonNull{ aToE }; // automatically determines the length QChar fToJ[]{ 'f', 'g', 'h', '\0', 'j' }; // uses given length, doesn't search for '\0', so '\0' at position 3 // is considered to be a part of the string similarly to 'h' and 'j QStringView nonNull{ fToJ, std::size(fToJ) }; QStringView part{ fToJ }; //stops on the first encounter of '\0'
Modelo de propiedad de las vistas
Como views no es propietaria de la memoria a la que hace referencia, hay que tener cuidado para asegurarse de que los datos referenciados (por ejemplo, propiedad de un QString) sobreviven al view en todas las rutas de código.
QStringView sayHello()
{
QString hello("Hello.");
return QStringView{ hello }; // hello gets out of scope and destroyed
}
void main()
{
QStringView hello{ sayHello() };
qDebug() << hello; // undefined behavior
}La conversión de un QStringView a QString
QStringView no convertirá implícita o explícitamente a un QString, pero puede crear una copia profunda de sus datos:
void print(const QString &s) { qDebug() << s; } void main() { QStringView string{ u"string"}; // print(string); // invalid, no implicit conversion // QString str{ string }; // invalid, no explicit conversion print(string.toString()); QString str = string.toString(); // create QString from view }
Notas importantes
Aprovechando las nuevas clases de vista, se puede conseguir un gran aumento del rendimiento en muchos casos de uso. Sin embargo, es importante saber que puede haber algunas advertencias. Por lo tanto, es importante recordar:
- Las vistas deben pasarse por valor, no por referencia-a-const.
- Construir una vista con una longitud negativa es un comportamiento indefinido.
- Se debe tener cuidado para asegurar que los datos referenciados (por ejemplo, propiedad de un QString) sobreviven a la vista en todas las rutas de código.
Clases relacionadas con String
La clase QStringView
A partir de Qt6 se recomienda generalmente usar QStringView en lugar de QStringRef. QStringView hace referencia a una porción contigua de una cadena UTF-16 que no posee. Actúa como un tipo de interfaz para todo tipo de cadenas UTF-16, sin necesidad de construir primero un QString. La clase QStringView expone casi todos los métodos de sólo lectura de QString y de la clase previamente existente QStringRef.
Nota: Se debe tener cuidado para asegurar que los datos de cadena referenciados (por ejemplo, propiedad de un QString) sobreviven al QStringView en todas las rutas de código.
Nota: Si un QStringView envuelve a un QString, hay que tener cuidado ya que a diferencia de QStringRef QStringView no actualizará el puntero de datos interno una vez que los datos de QString se reubiquen.
QString string = ...; QStringView view{string}; // Appending something very long might cause a relocation and will // ultimately result in a garbled QStringView. string += ...;
La clase QStringRef
En Qt6 QStringRef fue eliminada de Qt Core. Para facilitar la portabilidad de aplicaciones existentes sin tocar todo el código base, la clase QStringRef no desapareció completamente y en su lugar fue movida al módulo Qt5Compat. Si quieres seguir usando QStringRef, consulta Usando el módulo Qt5Compat.
Desafortunadamente, algunos métodos expuestos por QString que devuelven un QStringRef, no pudieron ser trasladados a Qt5Compat. Por lo tanto, puede ser necesaria alguna adaptación manual. Si su código utiliza una o más de las siguientes funciones, deberá adaptarlas para que utilicen QStringView o QStringTokenizer. También se recomienda utilizar QStringView::tokenize en lugar de QStringView::split para código de rendimiento crítico.
Cambie el código que utiliza QStringRef:
QString string = ...; QStringRef left = string.leftRef(n); QStringRef mid = string.midRef(n); QStringRef right = string.rightRef(n); QString value = ...; const QVector<QStringRef> refs = string.splitRef(' '); if (refs.contains(value)) return true;
a:
QString string = ...; QStringView left = QStringView{string}.left(n); QStringView mid = QStringView{string}.mid(n); QStringView right = QStringView{string}.right(n); QString value = ...; const QList<QStringView> refs = QStringView{string}.split(u' '); if (refs.contains(QStringView{value})) return true; // or const auto refs = QStringView{string}.tokenize(u' '); for (auto ref : refs) { if (ref == value) return true; }
QMutex y Clases Relacionadas
En Qt 6, QRecursiveMutex ya no hereda de QMutex. Este cambio se hizo para mejorar el rendimiento tanto de QMutex como de QRecursiveMutex.
Debido a estos cambios, el enum QMutex::RecursionMode ha sido eliminado, y QMutexLocker es ahora una clase templated que puede operar tanto en QMutex como en QRecursiveMutex.
QFuture y clases relacionadas
La clase QFuture
Para evitar el uso no intencionado de QFuture, hubo algunos cambios en la API de QFuture en Qt 6, que pueden introducir rupturas en la compatibilidad de fuentes.
Conversiones implícitas entre QFuture y otros tipos
Se ha desactivado la conversión de QFuture<T> a T. El operador de casting estaba llamando a QFuture::result(), lo que puede provocar un comportamiento indefinido si el usuario ha movido los resultados de QFuture a través de QFuture::takeResult() antes de intentar hacer la conversión. Utilice explícitamente los métodos QFuture::result() o QFuture::takeResult() cuando necesite convertir QFuture<T> a T.
También se ha desactivado la conversión implícita de QFuture<T> a QFuture<void>. Si realmente desea realizar la conversión, utilice el constructor explícito QFuture<void>(const QFuture<T> &):
Operadores de igualdad
Se han eliminado los operadores de igualdad de QFuture. Comparaban los punteros d subyacentes en lugar de comparar los resultados, que no es lo que los usuarios podrían esperar. Si necesita comparar objetos QFuture, utilice los métodos QFuture::result() o QFuture::takeResult(). Por ejemplo:
QFuture<int> future1 = ...; QFuture<int> future2 = ...; if (future1.result() == future2.result()) // ...
Cambios de comportamiento en QFuture y QFutureWatcher
En Qt 6, hubo algunas mejoras en QFuture y QFutureWatcher que causaron los siguientes cambios de comportamiento:
- Después de pausar QFuture o QFutureWatcher (llamando a
pause()osetPaused(true)), QFutureWatcher no dejará inmediatamente de entregar señales de progreso y de resultado listo. En el momento de la pausa puede haber cálculos en curso que no pueden detenerse. Las señales para tales cálculos pueden ser entregadas después de la pausa, en lugar de ser pospuestas y reportadas sólo después de la siguiente reanudación. Para ser notificado cuando la pausa ha tenido efecto, se puede utilizar la señal QFutureWatcher::suspended(). Además, hay nuevos métodosisSuspending()yisSuspended(), para comprobar si QFuture está en proceso de suspensión o ya está en estado suspendido. Nótese que por razones de consistencia, tanto para QFuture como para QFutureWatcher las APIs relacionadas con la pausa fueron obsoletas y reemplazadas por métodos similares que tienen "suspender" en el nombre en su lugar. - QFuture::waitForFinished() ahora esperará hasta que QFuture esté realmente en el estado finalizado, en lugar de salir tan pronto como no esté en el estado en ejecución. Esto evita que
waitForFinished()salga inmediatamente, si en el momento de llamarlo el futuro aún no se ha iniciado. Lo mismo se aplica a QFutureWatcher::waitForFinished(). Este cambio no afectará al comportamiento del código que utilizaba QFuture con QtConcurrent. Sólo el código que lo utilizaba con el indocumentadoQFutureInterfacepuede verse afectado. - QFutureWatcher::isFinished() refleja ahora el estado final de QFuture en lugar de devolver false hasta que QFutureWatcher::finished() haya sido emitido.
La clase QPromise
En Qt 6, la nueva clase QPromise debería usarse en lugar de la no oficial QFutureInterface como contrapartida "setter" de QFuture.
Clases IO
La clase QProcess
En Qt 6, la sobrecarga QProcess::start() que interpreta una única cadena de comandos dividiéndola en nombre de programa y argumentos pasa a llamarse QProcess::startCommand(). Sin embargo, existe una sobrecarga QProcess::start() que toma una sola cadena, así como un QStringList para los argumentos. Dado que el parámetro QStringList toma por defecto la lista vacía, el código existente que sólo pase una cadena seguirá compilando, pero fallará al ejecutar el proceso si se trata de una cadena de comandos completa que incluya argumentos.
Qt 5.15 introdujo advertencias de deprecación para la sobrecarga respectiva para facilitar el descubrimiento y la actualización del código existente:
QProcess process; // compiles with warnings in 5.15, compiles but fails with Qt 6 process.start("dir \"My Documents\""); // works with both Qt 5 and Qt 6; also see QProcess::splitCommand() process.start("dir", QStringList({"My Documents"}); // works with Qt 6 process.startCommand("dir \"My Documents\"");
QProcess::pid() y el tipo Q_PID han sido eliminados; utilice QProcess::processId() en su lugar para obtener el identificador nativo del proceso. El código que utiliza las API nativas de Win32 para acceder a los datos de Q_PID como una estructura Win32 PROCESS_INFORMATION ya no está soportado.
Sistema de metatipos
La clase QVariant
QVariant ha sido reescrita para utilizar QMetaType en todas sus operaciones. Esto implica cambios de comportamiento en algunos métodos:
QVariant::isNull()ahora sólo devuelvetruesi elQVariantestá vacío o contiene unnullptr. En Qt 5, también devolvía true para las clases en qtbase que tenían un métodoisNullen sí mismas si éste devolvía true. El código que se basa en el comportamiento antiguo necesita comprobar si el valor contenido devuelve isNull - sin embargo, es poco probable que tal código ocurra en la práctica, ya queisNull()es raramente la propiedad en la que uno está interesado (compareQString::isEmpty()/isNull()yQTime::isValid/isNull).QVariant::operator==utilizaQMetaType::equalsen Qt 6. Por lo tanto, algunos tipos que carecen de un operador de igualdad adecuado (comoQPixmapoQIcon) nunca compararán iguales. Además, los números de coma flotante almacenados enQVariantya no se comparan conqFuzzyCompare, sino que utilizan comparaciones exactas.
Además, se han eliminado QVariant::operator<, QVariant::operator<=, QVariant::operator> y QVariant::operator>=, porque las distintas variantes no siempre son ordenables. Esto también significa que QVariant ya no se puede utilizar como clave en un QMap.
La clase QMetaType
En Qt 6, el registro de comparadores y operadores de flujo QDebug y QDataStream se realiza automáticamente. En consecuencia, QMetaType::registerEqualsComparator(), QMetaType::registerComparators(), qRegisterMetaTypeStreamOperators() y QMetaType::registerDebugStreamOperator() ya no existen. Las llamadas a estos métodos deben eliminarse al portar a Qt 6.
Registro de tipos
Los tipos utilizados en Q_PROPERTY tienen su meta-tipo almacenado en la clase QMetaObject. Esto requiere que los tipos estén completos cuando moc los vea, lo que puede llevar a errores de compilación en código que funcionaba en Qt 5. Hay tres formas de solucionar este problema:
- Incluir la cabecera que define el tipo.
- En lugar de utilizar un include, utilice la macro
Q_MOC_INCLUDE. Esto ayuda si incluir la cabecera causaría una dependencia cíclica, o cuando ralentizaría la compilación. - Si la cabecera está presente en el archivo cpp que implementa la clase, también es posible incluir allí el archivo generado por moc.
Clases de expresiones regulares
La clase QRegularExpression
En Qt 6, la clase QRegExp ha sido retirada al módulo Qt5Compat y todas las APIs de Qt que la usaban han sido eliminadas de otros módulos. El código cliente que lo utilizaba puede ser portado para utilizar QRegularExpression en su lugar. Como QRegularExpression ya está presente en Qt 5, esto puede hacerse y probarse antes de la migración a Qt 6.
La clase QRegularExpression introducida en Qt 5 implementa expresiones regulares compatibles con Perl y es una gran mejora sobre QRegExp en términos de APIs ofrecidas, sintaxis de patrones soportada y velocidad de ejecución. La mayor diferencia es que QRegularExpression simplemente contiene una expresión regular, y no se modifica cuando se solicita una coincidencia. En su lugar, se devuelve un objeto QRegularExpressionMatch, para comprobar el resultado de una coincidencia y extraer la subcadena capturada. Lo mismo se aplica a las coincidencias globales y a QRegularExpressionMatchIterator.
A continuación se indican otras diferencias.
Nota: QRegularExpression no soporta todas las características disponibles en las expresiones regulares compatibles con Perl. La más notable es el hecho de que los nombres duplicados para capturar grupos no están soportados, y su uso puede llevar a un comportamiento indefinido. Esto puede cambiar en una futura versión de Qt.
Diferente sintaxis de patrones
Portar una expresión regular de QRegExp a QRegularExpression puede requerir cambios en el propio patrón.
En escenarios específicos, QRegExp era demasiado indulgente y aceptaba patrones que son simplemente inválidos cuando se usa QRegularExpression. Esto es fácil de detectar, porque los objetos QRegularExpression construidos con estos patrones no son válidos (véase QRegularExpression::isValid()).
En otros casos, un patrón portado de QRegExp a QRegularExpression puede cambiar silenciosamente de semántica. Por lo tanto, es necesario revisar los patrones utilizados. Los casos más notables de incompatibilidad silenciosa son:
- Se necesitan llaves para utilizar un escape hexadecimal como
\xHHHHcon más de 2 dígitos. Un patrón como\x2022necesita ser portado a\x{2022}, o coincidirá con un espacio (0x20) seguido de la cadena"22". En general, se recomienda encarecidamente utilizar siempre llaves con el escape\x, independientemente del número de dígitos especificados. - Una cuantificación de 0 a n como
{,n}debe pasarse a{0,n}para conservar la semántica. De lo contrario, un patrón como\d{,3}coincidiría con un dígito seguido de la cadena exacta"{,3}". - QRegExp por defecto hace coincidencias con Unicode, mientras que QRegularExpression requiere una opción aparte; para más detalles, véase más abajo.
- c{.} en QRegExp coincide por defecto con todos los caracteres, incluido el carácter de nueva línea. QRegularExpression excluye por defecto el carácter de nueva línea. Para incluir el carácter de nueva línea, establezca la opción de patrón QRegularExpression::DotMatchesEverythingOption.
Para una visión general de la sintaxis de expresiones regulares soportada por QRegularExpression, por favor consulte la página man pcrepattern(3), que describe la sintaxis de patrones soportada por PCRE (la implementación de referencia de expresiones regulares compatibles con Perl).
Portar desde QRegExp::exactMatch()
QRegExp::exactMatch() servía para dos propósitos: comparaba exactamente una expresión regular con una cadena de asunto, e implementaba comparaciones parciales.
Adaptación de la correspondencia exacta de QRegExp
La coincidencia exacta indica si la expresión regular coincide con toda la cadena de asunto. Por ejemplo, las clases rinden en la cadena de asunto "abc123":
| QRegExp::exactMatch() | QRegularExpressionMatch::hasMatch() | |
|---|---|---|
"\\d+" | falso | verdadero |
"[a-z]+\\d+" | verdadero | verdadero |
La coincidencia exacta no se refleja en QRegularExpression. Si desea asegurarse de que la cadena de asunto coincide exactamente con la expresión regular, puede envolver el patrón utilizando la función QRegularExpression::anchoredPattern():
QString p("a .*|pattern"); // re matches exactly the pattern string p QRegularExpression re(QRegularExpression::anchoredPattern(p));
Adaptación de la concordancia parcial de QRegExp
Cuando se utilizaba QRegExp::exactMatch(), si no se encontraba una coincidencia exacta, se podía averiguar qué parte de la cadena de asunto coincidía con la expresión regular llamando a QRegExp::matchedLength(). Si la longitud devuelta era igual a la longitud de la cadena de asunto, se podía concluir que se había encontrado una coincidencia parcial.
QRegularExpression admite explícitamente las coincidencias parciales mediante el correspondiente QRegularExpression::MatchType.
Coincidencia global
Debido a las limitaciones de la API de QRegExp, ha sido imposible implementar correctamente las coincidencias globales (es decir, como lo hace Perl). En particular, los patrones que pueden coincidir con 0 caracteres (como "a*") son problemáticos.
QRegularExpression::globalMatch() implementa la concordancia global de Perl correctamente, y el iterador devuelto puede utilizarse para examinar cada resultado.
Por ejemplo, si tiene código como:
QString subject("the quick fox"); int offset = 0; QRegExp re("(\\w+)"); while ((offset = re.indexIn(subject, offset)) != -1) { offset += re.matchedLength(); // ... }
Puede reescribirlo como:
QString subject("the quick fox"); QRegularExpression re("(\\w+)"); QRegularExpressionMatchIterator i = re.globalMatch(subject); while (i.hasNext()) { QRegularExpressionMatch match = i.next(); // ... }
Soporte de propiedades Unicode
Cuando se utiliza QRegExp, las clases de caracteres como \w, \d, etc. coinciden con caracteres con la propiedad Unicode correspondiente: por ejemplo, \d coincide con cualquier carácter con la propiedad Unicode Nd (dígito decimal).
Estas clases de caracteres sólo coinciden por defecto con caracteres ASCII cuando se utiliza QRegularExpression: por ejemplo, \d coincide exactamente con un carácter del rango ASCII 0-9. Es posible cambiar este comportamiento utilizando la opción de patrón QRegularExpression::UseUnicodePropertiesOption.
Comodines
No hay una forma directa de hacer coincidencias con comodines en QRegularExpression. Sin embargo, se proporciona el método QRegularExpression::wildcardToRegularExpression() para traducir patrones glob a una expresión regular compatible con Perl que puede utilizarse para ese propósito.
Por ejemplo, si tiene código como:
Puede reescribirlo como:
auto wildcard = QRegularExpression(QRegularExpression::wildcardToRegularExpression("*.txt"));
Tenga en cuenta, sin embargo, que algunos patrones comodín tipo shell pueden no ser traducidos a lo que usted espera. El siguiente código de ejemplo se romperá silenciosamente si simplemente se convierte utilizando la función mencionada anteriormente:
const QString fp1("C:/Users/dummy/files/content.txt"); const QString fp2("/home/dummy/files/content.txt"); QRegExp re1("*/files/*"); re1.setPatternSyntax(QRegExp::Wildcard); re1.exactMatch(fp1); // returns true re1.exactMatch(fp2); // returns true // but converted with QRegularExpression::wildcardToRegularExpression() QRegularExpression re2(QRegularExpression::wildcardToRegularExpression("*/files/*")); re2.match(fp1).hasMatch(); // returns false re2.match(fp2).hasMatch(); // returns false
Esto se debe a que, por defecto, la expresión regular devuelta por QRegularExpression::wildcardToRegularExpression() está totalmente anclada. Para obtener una expresión regular que no esté anclada, pase QRegularExpression::UnanchoredWildcardConversion como las opciones de conversión:
QRegularExpression re3(QRegularExpression::wildcardToRegularExpression( "*/files/*", QRegularExpression::UnanchoredWildcardConversion)); re3.match(fp1).hasMatch(); // returns true re3.match(fp2).hasMatch(); // returns true
Correspondencia mínima
QRegExp::setMinimal() implementa la concordancia mínima simplemente invirtiendo la codicia de los cuantificadores (QRegExp no soporta cuantificadores perezosos, como *?, +?, etc.). QRegularExpression en cambio sí soporta cuantificadores codiciosos, perezosos y posesivos. La opción de patrón QRegularExpression::InvertedGreedinessOption puede ser útil para emular los efectos de QRegExp::setMinimal(): si está activada, invierte la codicia de los cuantificadores (los codiciosos se convierten en perezosos y viceversa).
Modos de intercalación
La opción de coincidencia QRegularExpression::AnchorAtOffsetMatchOption puede utilizarse para emular el comportamiento de QRegExp::CaretAtOffset. No hay equivalente para los otros modos de QRegExp::CaretMode.
La clase QRegExp
En Qt6 QRegExp fue eliminado de Qt Core. Si tu aplicación no puede ser portada ahora mismo, QRegExp todavía existe en Qt5Compat para mantener estas bases de código funcionando. Si quieres seguir usando QRegExp, consulta Usando el módulo Qt5Compat.
QEvent y subclases
La clase QEvent define un constructor de copia y un operador de asignación, a pesar de ser una clase polimórfica. Copiar clases con métodos virtuales puede resultar en slicing cuando se asignan objetos de diferentes clases entre sí. Dado que copiar y asignar a menudo ocurre de forma implícita, esto podría llevar a problemas difíciles de depurar.
En Qt 6, el constructor de copia y el operador de asignación para las subclases de QEvent se han hecho protegidos para evitar la copia implícita. Si necesita copiar eventos, utilice el método clone, que devolverá una copia del objeto QEvent asignada al montón. Asegúrate de borrar el clon, quizás usando std::unique_ptr, a menos que lo publiques (en cuyo caso Qt lo borrará una vez que haya sido entregado).
En tus subclases de QEvent, anula clone(), y declara el constructor de copia protegido e implementado por defecto y el operador de asignación así:
class MyEvent : public QEvent { public: // ... MyEvent *clone() const override { return new MyEvent(*this); } protected: MyEvent(const MyEvent &other) = default; MyEvent &operator=(const MyEvent &other) = default; MyEvent(MyEvent &&) = delete; MyEvent &operator=(MyEvent &&) = delete; // member data };
Ten en cuenta que si tu clase MyEvent asigna memoria (por ejemplo, a través de un patrón puntero-a-implementación), entonces tendrás que implementar una semántica de copia personalizada.
Clases de serialización
En Qt 6, los métodos de QJsonDocument para convertirlo a/desde el formato binario JSON heredado de Qt fueron eliminados en favor del formato estandarizado CBOR. Los tipos JSON de Qt pueden convertirse a tipos CBOR de Qt, que a su vez pueden serializarse al formato binario CBOR y viceversa. Véase, por ejemplo, QCborValue::fromJsonValue() y QCborValue::toJsonValue().
Si todavía necesitas usar el formato binario JSON, puedes usar los reemplazos proporcionados en el módulo Qt5Compat. Pueden encontrarse en el espacio de nombres QBinaryJson. Ver Usando el módulo Qt5Compat para saber cómo usar el módulo en tu aplicación.
Otras clases
En Qt 5, QCoreApplication::quit() era equivalente a llamar a QCoreApplication::exit(). Esto simplemente salía del bucle de eventos principal.
En Qt 6, el método intentará cerrar todas las ventanas de nivel superior enviando un evento close. Las ventanas son libres de cancelar el proceso de cierre ignorando el evento.
Llama a QCoreApplication::exit() para mantener el comportamiento no condicional.
QLibraryInfo::location() y QLibraryInfo::Location fueron obsoletos debido a nombres inconsistentes. Usa la nueva API QLibraryInfo::path() y QLibraryInfo::LibraryPath en su lugar.
Qt State Machine El framework
Qt State Machine se trasladó al módulo Qt SCXML (que pronto pasará a llamarse Qt State Machines) y, por lo tanto, ya no forma parte de Qt Core. Había muy pocas dependencias cruzadas dentro de Qt Core, lo que finalmente llevó a tomar esta decisión.
Uso del módulo Qt5Compat
Para usar el módulo Qt5Compat, necesitas compilar con sus cabeceras en tu ruta de inclusión y enlazar con su librería. Si estás usando qmake, añade lo siguiente a tu archivo .pro:
QT += core5compat
Si compila su aplicación o biblioteca utilizando cmake, añada lo siguiente a su CMakeList.txt:
PUBLIC_LIBRARIES
Qt::Core5CompatQTextStream
Eliminado QTextStream::setCodec(). Usa QTextStream::setEncoding() con la nueva Encoding enum en su lugar.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.