Reputation: 2658
I have what I thought was something simple. Declarations in class header:
public:
int index; // just your vanilla integer
QString *qspointer; // allocated array with space for 1000 pointers
// allocation occurs first thing in class code: it's definitely there
code:
index = 0; // works
qspointer[index] = new QString(); // causes error
alternate code
QString *qs; // works
qs = new QString(); // works
qspointer[index] = qs; // causes error
The compile error in either case is:
"invalid conversion from QString to char"
"initializing argument 1 of 'QString& QString::operator=(char)"
it's a QString pointer. I have an array of QString pointers. I simply want to put the pointer in the array of pointers. This works fine with non-class items like int pointers, character pointers, etc. It's as if this isn't actually an array of QString pointers. But... nearby, I have this code:
qspointers[index].~QString(); // compiler likes this.
Which... if this wasn't an array of QString pointers... should cause an error. But it doesn't. I am so confused. :)
I'm clearly missing something fundamental; appreciate any pointers (hah)
Upvotes: 1
Views: 1358
Reputation: 98425
Given that QString
s are implicitly shared value classes (and also support move semantics since Qt 4.8), and that we're using C++ and not C, and the year is 2016, the last thing you should be doing is messing with pointers to strings like it was 1980s.
Here's what you want:
QVector<QString> strings(1000); // 1000 empty strings
strings[0] = "Foo";
strings[1] = "Bar";
strings.push_back("Moo");
Q_ASSERT(strings.back() == "Moo");
This would also be true if you were using std::string
:
QVector<std::string> strings(1000);
// etc.
If your array has a fixed size, you should use std::array
instead:
std::array<QString, 1000> strings;
strings[0] = "Foo";
strings[1] = "Bar";
Note that none of the above code will be slower than the way you presumably intend to do it:
QString *strings[1000];
strings[0] = new QString("Foo");
strings[1] = new QString("Bar");
But that's not all, of course. You need to ensure that the strings don't leak, and - presumably - that any unallocated strings aren't just dangling pointers. And of course you don't want anyone attempting to copy that array blindly:
// DO NOT EVEN THINK OF DOING IT THIS WAY!
class MyClass {
Q_DISABLE_COPY(MyClass)
QString *strings[1000];
public:
MyClass() { memset(&strings, 0, sizeof(strings)); }
// Note: calling delete with a null pointer is perfectly safe
~MyClass() { for (auto string : strings) delete string; }
void setString(int index, const QString & value) {
if (!strings[index])
strings[index] = new QString(value);
else
*strings[index] = value;
}
QString string(int index) const {
return strings[index] ? *strings[index] : QString();
}
};
That way of doing it is horrible absolutely uncalled for in 2016. If your platform is too old to use std::array
, use QVarLengthArray
: it is like std::array
that can optionally dynamically resize itself. And store those strings by value, not by pointer!.
The in-place lifetime management of strings you're doing by calling the destructor etc. is harrowing and has absolutely no place outside of specialized classes that deal with resource management. What does it mean in plain-English terms? It means that if you have benchmarking results that show that normal containers are somehow too slow and you've determined that your algorithms aren't to blame but simply need a specialized container to support said specialized algorithms then you should write a custom container that manages the collection of strings. And then use that container in your code, with nastiness encapsulated away. In 99.9999% of cases, you will not want to implement any such container. The standard library and Qt containers are plenty clever. Use them appropriately and you should be all set.
Upvotes: 1
Reputation: 8238
qspointer[index] = new QString();
qspointer
is a pointer to QString(s), which, probably, points at an array and may be indexed. Thus, qspointer[index]
is a QString
. To be more precise, qspointer[index]
expression returns a reference to QString
. new QString();
returns a pointer, so what you are trying to do in this line looks like
QString *ptr = whatever;
QString s = ptr;
which is obviously an error. Analogically,
qspointer[index] = qs;
has the same problem.
I have an array of QString pointers.
Looks like you don't. QString *qspointer;
is a pointer to an array of QString
, not an array of pointers.
To make an array of pointers, you need something like this:
// Declaration:
QString **qspointer; // Pointer to pointers
// Allocation:
qspointer = new QString*[1000]; // Allocated array of 1000 pointers
// Putting a pointer into the array of pointers:
qspointer[index] = new QString();
Next,
qspointers[index].~QString();
compiles, because calling a member by .
is allowed for an object or a reference.
Finally, calling a destructor explicitly is usually a bad idea. Use delete
for heap-allocated objects and delete[]
for arrays. Note that having a pointer, you can't determine if it points to a single object or an array.
Upvotes: 1