尝试创建 Qt 4.7 QStrings,填充到指针数组中

Trying to create Qt 4.7 QStrings, stuff into array of pointers

我有我认为简单的东西。 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

代码:

index = 0;                        // works
qspointer[index] = new QString(); // causes error

备用代码

QString *qs;                      // works
qs = new QString();               // works
qspointer[index] = qs;            // causes error

两种情况下的编译错误是:

"invalid conversion from QString to char"
"initializing argument 1 of 'QString& QString::operator=(char)"

它是一个 QString 指针。我有一个 QString 指针数组。我只是想把指针 放在 指针数组中。这适用于 non-class 项目,如 int 指针、字符指针等。就好像这实际上不是 QString 指针数组一样。但是...在附近,我有这个代码:

qspointers[index].~QString(); // compiler likes this.

这...如果这不是 QString 指针数组...应该会导致错误。但事实并非如此。我感到很困惑。 :)

我显然遗漏了一些基本的东西;感谢任何指点(哈)

qspointer[index] = new QString();

qspointer 是一个指向 QString(s) 的指针,它可能指向一个数组并且可以被索引。因此,qspointer[index] 是一个 QString。更准确地说,qspointer[index] 表达式 returns 对 QString 的引用。 new QString(); returns 一个指针,所以你在这一行中试图做的事情看起来像

QString *ptr = whatever;
QString s = ptr;

这显然是一个错误。以此类推,

qspointer[index] = qs;

有同样的问题

I have an array of QString pointers.

看起来你没有。 QString *qspointer; 是指向 QString 数组的指针,而不是指针数组。

要创建指针数组,您需要这样的东西:

// 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();

接下来,

qspointers[index].~QString();

编译,因为对象或引用允许通过 . 调用成员。

最后,显式调用析构函数通常是bad idea。对堆分配的对象使用 delete,对数组使用 delete[]。请注意,有一个指针,您无法确定它是指向单个对象还是指向数组。

鉴于 QStrings 是隐式共享值 类(并且自 Qt 4.8 起还支持移动语义),并且我们使用的是 C++ 而不是 C,并且年份是 2016 年,您应该做的最后一件事就是像 1980 年代那样弄乱指向字符串的指针。

这是你想要的:

QVector<QString> strings(1000); // 1000 empty strings
strings[0] = "Foo";
strings[1] = "Bar";
strings.push_back("Moo");
Q_ASSERT(strings.back() == "Moo");

如果您使用 std::string:

,这也是正确的
QVector<std::string> strings(1000);
// etc.

如果你的数组有固定大小,你应该使用std::array代替:

std::array<QString, 1000> strings;
strings[0] = "Foo";
strings[1] = "Bar";

请注意,上述代码的 none 将比您可能打算执行的方式慢:

QString *strings[1000];
strings[0] = new QString("Foo");
strings[1] = new QString("Bar");

但这当然不是全部。您需要确保字符串不会泄漏,并且 - 大概 - 任何未分配的字符串不仅仅是悬挂指针。当然,您不希望任何人试图盲目复制该数组:

// 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();
  }
};

这种做法在 2016 年是绝对不需要的。如果您的平台太旧而无法使用 std::array,请使用 QVarLengthArray:就像 std::array 一样,可以选择动态调整自身大小。 按值存储这些字符串,而不是按指针!

通过调用析构函数等对字符串进行就地生命周期管理令人痛心,除了处理资源管理的专门 类 之外绝对没有其他地方。用简单的英语来说是什么意思?这意味着如果您的基准测试结果表明普通容器在某种程度上太慢并且您已经确定您的算法不是罪魁祸首但只需要一个专用容器来支持所述专用算法 然后 您应该编写一个自定义容器来管理字符串集合。然后在您的代码中使用该容器,将脏东西封装起来。在 99.9999% 的情况下,您不会想要实现任何此类容器。标准库和 Qt 容器非常聪明。适当地使用它们,你应该一切就绪。