是否有可能有一个复制构造 class 包含 std::unique_ptr<Base> 避免切片而不 Base 暴露 "clone" 函数?
Is it possible to have a copy constructible class that holds a std::unique_ptr<Base> avoiding slicing without Base exposing a "clone" function?
有没有办法为 class(比如 Copyable
编写一个复制构造函数,其中包含 std::unique_ptr
到 Base
class(但实际上是在存储 Derived
个对象。
快速测试显示发生了预期的切片,因为 Copyable
不知道它持有的真实类型。所以我想需要一个 clone
方法,但我想知道是否有办法让编译器以更好的方式处理这个问题?
切片代码:
#include <algorithm>
#include <iostream>
#include <memory>
struct Base
{
Base(int i = 0) : i(i) {}
virtual ~Base() = default;
int i;
virtual int f() { return i; }
};
struct Derived : Base
{
Derived() = default;
virtual int f() override { return 42; }
};
struct Copyable
{
Copyable(std::unique_ptr<Base>&& base) : data(std::move(base)) {}
Copyable(const Copyable& other)
{
data = std::make_unique<Base>(*other.data);
}
std::unique_ptr<Base> data;
};
int main()
{
Copyable c(std::make_unique<Derived>());
Copyable c_copy = c;
std::cout << c_copy.data->f() << '\n';
}
clone
代码:
#include <algorithm>
#include <iostream>
#include <memory>
struct Base
{
Base(int i = 0) : i(i) {}
virtual ~Base() = default;
int i;
virtual int f() { return i; }
virtual Base* clone() { return new Base(i); }
};
struct Derived : Base
{
Derived() = default;
virtual int f() override { return 42; }
virtual Derived* clone() override { return new Derived(); }
};
struct Copyable
{
Copyable(std::unique_ptr<Base>&& base) : data(std::move(base)) {}
Copyable(const Copyable& other)
{
data.reset(other.data->clone());
}
std::unique_ptr<Base> data;
};
int main()
{
Copyable c(std::make_unique<Derived>());
Copyable c_copy = c;
std::cout << c_copy.data->f() << '\n';
}
显然克隆代码有效。问题是,其中有些东西我想避免:
- 原始
new
.
- 需要成为界面一部分的随机函数。
- 这个函数returns一个原始指针。
- 此 class 的每个想要可复制的用户都需要调用此函数。
那么,有 "clean" 替代方案吗?
请注意,出于所有显而易见的原因,我想使用智能指针,我只需要深度复制 std::unique_ptr
。类似于 std::copyable_unique_ptr
,将可选的移动语义与深度复制复制构造函数相结合。这是最干净的方法吗?或者这只会增加混乱?
您当然可以为任何您知道如何静态克隆的对象创建 clone_ptr
-class。
它将保存一个指向对象的指针,以及一个指向用于克隆所述对象的函数的指针,可能来自转换无状态 lambda。
有没有办法为 class(比如 Copyable
编写一个复制构造函数,其中包含 std::unique_ptr
到 Base
class(但实际上是在存储 Derived
个对象。
快速测试显示发生了预期的切片,因为 Copyable
不知道它持有的真实类型。所以我想需要一个 clone
方法,但我想知道是否有办法让编译器以更好的方式处理这个问题?
切片代码:
#include <algorithm>
#include <iostream>
#include <memory>
struct Base
{
Base(int i = 0) : i(i) {}
virtual ~Base() = default;
int i;
virtual int f() { return i; }
};
struct Derived : Base
{
Derived() = default;
virtual int f() override { return 42; }
};
struct Copyable
{
Copyable(std::unique_ptr<Base>&& base) : data(std::move(base)) {}
Copyable(const Copyable& other)
{
data = std::make_unique<Base>(*other.data);
}
std::unique_ptr<Base> data;
};
int main()
{
Copyable c(std::make_unique<Derived>());
Copyable c_copy = c;
std::cout << c_copy.data->f() << '\n';
}
clone
代码:
#include <algorithm>
#include <iostream>
#include <memory>
struct Base
{
Base(int i = 0) : i(i) {}
virtual ~Base() = default;
int i;
virtual int f() { return i; }
virtual Base* clone() { return new Base(i); }
};
struct Derived : Base
{
Derived() = default;
virtual int f() override { return 42; }
virtual Derived* clone() override { return new Derived(); }
};
struct Copyable
{
Copyable(std::unique_ptr<Base>&& base) : data(std::move(base)) {}
Copyable(const Copyable& other)
{
data.reset(other.data->clone());
}
std::unique_ptr<Base> data;
};
int main()
{
Copyable c(std::make_unique<Derived>());
Copyable c_copy = c;
std::cout << c_copy.data->f() << '\n';
}
显然克隆代码有效。问题是,其中有些东西我想避免:
- 原始
new
. - 需要成为界面一部分的随机函数。
- 这个函数returns一个原始指针。
- 此 class 的每个想要可复制的用户都需要调用此函数。
那么,有 "clean" 替代方案吗?
请注意,出于所有显而易见的原因,我想使用智能指针,我只需要深度复制 std::unique_ptr
。类似于 std::copyable_unique_ptr
,将可选的移动语义与深度复制复制构造函数相结合。这是最干净的方法吗?或者这只会增加混乱?
您当然可以为任何您知道如何静态克隆的对象创建 clone_ptr
-class。
它将保存一个指向对象的指针,以及一个指向用于克隆所述对象的函数的指针,可能来自转换无状态 lambda。