Think about what this line of code does:
QImage scaledImage = scaledImage.mirrored(true, true); // Crash
- The symbol
scaledImage
is defined. This scaledImage
symbol name overrides the one of the same name in the outer scope.
- Calls the mirrored() method.
scaledImage
is now created using the copy constructor with the output of mirrored().
As PeterT points out in the comments, this is undefined behavior: you're calling a method on an object before it's created. In this case crashing helped you avoid a mistake that's easy to make.
Here's an example that demonstrates exactly how and why this problem exists:
class Tester {
public:
Tester() {
qDebug() << "Default c'tor";
}
Tester( const Tester& other ) {
qDebug() << "Copy c'tor";
}
Tester& Tester::operator=( const Tester& other ) {
qDebug() << "Assignment";
return *this;
}
Tester& test() {
data = "test";
return *this;
}
};
int main(int argc, char *argv[])
{
Q_UNUSED(argc);
Q_UNUSED(argv);
Tester test = test.test();
return 0;
}
The program will output the following:
Test
Copy c'tor
In other words, the test() method was called before any constructor was called. That's bad!
But it gets much worse if we modify our example with a data member:
class Tester {
QString data;
public:
Tester() {
qDebug() << "Default c'tor";
data = "data";
}
Tester( const Tester& other ) {
qDebug() << "Copy c'tor";
data = other.data;
}
Tester& Tester::operator=( const Tester& other ) {
qDebug() << "Assignment";
data = other.data;
return *this;
}
Tester& test() {
data = "test";
qDebug() << "Test";
return *this;
}
};
Now the program crashes before anything can be printed out. Specifically, the first line in test() is the culprit:
data = "test";
If you think about it, this is trying to assign something to a QString that hasn't yet been constructed. Any attempt to access or modify the member variables of an unconstructed object is bad news.