После последнего ответа в рекомендованной ссылке
Как мне сделать new[]
инициализацию по умолчанию для массива примитивных типов? ,
Я придумал следующий небольшой пример :
#include <iostream>
#include <memory>
#include <string>
class Widget {
private:
std::string _name;
public:
Widget(const char *name): _name(name) { }
Widget(const Widget&) = delete;
const std::string& name() const { return _name; }
};
int main()
{
const int n = 3;
std::unique_ptr<Widget[]> ptrLabels(
new Widget[n]{
Widget("label 1"),
Widget("label 2"),
Widget("label 3")
});
for (int i = 0; i < n; ++i) {
std::cout << ptrLabels[i].name() << '\n';
}
return 0;
}
Выход:
label 1
label 2
label 3
Демонстрация в реальном времени на coliru
Хитрость заключается в использовании списка инициализаторов.
Я был немного не уверен, включает ли это конструкцию копирования (что часто запрещено в библиотеках классов виджетов). Чтобы быть уверенным, я написал Widget(const Widget&) = delete;
.
Я должен признать, что это работает с C ++ 17, но не раньше.
Я немного поиграл с первым примером.
Я пробовал также
new Widget[n]{
{ "label 1" },
{ "label 2" },
{ "label 3" }
});
с успехом, пока я не понял, что я забыл сделать конструктор explicit
в первом примере. (Обычно набор виджетов не позволяет этому - предотвращать случайное преобразование.) После исправления он больше не компилируется.
Представляем конструктор перемещения, который компилируется даже с C ++ 11:
#include <iostream>
#include <memory>
#include <string>
class Widget {
private:
std::string _name;
public:
explicit Widget(const char *name): _name(name) { }
Widget(const Widget&) = delete;
Widget(const Widget &&widget): _name(std::move(widget._name)) { }
const std::string& name() const { return _name; }
};
int main()
{
const int n = 3;
std::unique_ptr<Widget[]> ptrLabels(
new Widget[n]{
Widget("label 1"),
Widget("label 2"),
Widget("label 3")
});
for (int i = 0; i < n; ++i) {
std::cout << ptrLabels[i].name() << '\n';
}
return 0;
}
Вывод: как выше
Демонстрация в реальном времени на coliru