如何初始化由 unique_ptr 管理的数组的元素?
How to initialize elements of an array managed by a unique_ptr?
我们知道资源获取是初始化 (RAII),我寻找语法来初始化具有参数(没有默认参数)的对象数组,由 unique_ptr
管理,但我没有找到任何比如Cppreference中有一个构造int
int size = 10;
std::unique_ptr<int[]> fact(new int[size]);
我怎么能这样写:
class Widget
{
Widget(int x, in y):x_(x),y_(y)
{}
int x_,y_;
};
std::unique_ptr<Widget[]> fact(new Widget[size]);
根据推荐的link
How can I make new[]
default-initialize the array of primitive types?,
中的最后一个答案,我想出了以下小例子:
#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
诀窍是使用初始化列表。
我有点不确定这是否涉及复制构造(这在小部件 class 库中通常被禁止)。可以肯定的是,我写了 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;
}
输出:如上
您可以使用放置新的和自定义的删除器:
class Widget {
public:
int i;
Widget(int i) : i(i) {}
~Widget() { std::cout << i; }
};
class WidgetDeleter {
int _size;
public:
WidgetDeleter(int size) : _size(size) {}
void operator()(Widget* w) {
for (int i = 0; i < _size; ++i) w[i].~Widget();
}
};
void main() {
const int widgetsCount = 10;
auto widgets = std::unique_ptr<Widget[], WidgetDeleter>(
(Widget*)(new byte[widgetsCount * sizeof(Widget)]), WidgetDeleter(widgetsCount));
for (int i = 0; i < widgetsCount; ++i) new (widgets.get() + i)Widget(i);
for (int i = 0; i < widgetsCount; ++i) std::cout << widgets[i].i;
std::cout << std::endl;
}
正如预期的那样,我们有两行输出:
0123456789
0123456789
观察,因为删除器在这里是有状态的,所以不可能使用 std::unique_ptr<Widget[], WidgetDeleter>
[unique.ptr.single.ctor#8]
的默认构造函数
我们知道资源获取是初始化 (RAII),我寻找语法来初始化具有参数(没有默认参数)的对象数组,由 unique_ptr
管理,但我没有找到任何比如Cppreference中有一个构造int
int size = 10;
std::unique_ptr<int[]> fact(new int[size]);
我怎么能这样写:
class Widget
{
Widget(int x, in y):x_(x),y_(y)
{}
int x_,y_;
};
std::unique_ptr<Widget[]> fact(new Widget[size]);
根据推荐的link
How can I make new[]
default-initialize the array of primitive types?,
中的最后一个答案,我想出了以下小例子:
#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
诀窍是使用初始化列表。
我有点不确定这是否涉及复制构造(这在小部件 class 库中通常被禁止)。可以肯定的是,我写了 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;
}
输出:如上
您可以使用放置新的和自定义的删除器:
class Widget {
public:
int i;
Widget(int i) : i(i) {}
~Widget() { std::cout << i; }
};
class WidgetDeleter {
int _size;
public:
WidgetDeleter(int size) : _size(size) {}
void operator()(Widget* w) {
for (int i = 0; i < _size; ++i) w[i].~Widget();
}
};
void main() {
const int widgetsCount = 10;
auto widgets = std::unique_ptr<Widget[], WidgetDeleter>(
(Widget*)(new byte[widgetsCount * sizeof(Widget)]), WidgetDeleter(widgetsCount));
for (int i = 0; i < widgetsCount; ++i) new (widgets.get() + i)Widget(i);
for (int i = 0; i < widgetsCount; ++i) std::cout << widgets[i].i;
std::cout << std::endl;
}
正如预期的那样,我们有两行输出:
0123456789
0123456789
观察,因为删除器在这里是有状态的,所以不可能使用 std::unique_ptr<Widget[], WidgetDeleter>
[unique.ptr.single.ctor#8]