对多态对象成员的无效引用
Invalidated references to members of polymorphic objects
假设我有两个类Foo
和Bar
继承接口Base
,并希望将这些类的实例存储在类型为std::vector<std::unique_ptr<Base>>
的向量中。Bar
类型的对象应该存储对值的引用(在本场景中,该值是Foo
类的成员)。从概念上讲,我想实现以下目标:
#include <iostream>
#include <memory>
#include <vector>
template<typename Type, typename ... Types>
std::unique_ptr<Type> make_unique(Types &&... arguments) {
return std::unique_ptr<Type>(new Type(std::forward<Types>(arguments)...));
}
class Base {
public:
virtual ~Base() = 0;
virtual void execute() = 0;
};
Base::~Base() {
}
class Foo: public Base {
public:
void execute() override {
// Foo-specific implementation of execute(), may change value_
value_ = 2;
}
const int & value() const {
return value_;
}
private:
int value_;
};
class Bar: public Base {
public:
Bar(const int &value) : value_(value) {}
void execute() override {
// Bar-specific implementation of execute(), uses current value_
std::cout << value_ << std::endl;
}
private:
const int &value_; // Reference to a value, not necessarily from Foo
};
int main() {
// Collection of base objects, possibly inside another object
std::vector<std::unique_ptr<Base>> baseVector;
baseVector.emplace_back(make_unique<Foo>());
baseVector.emplace_back(make_unique<Bar>(
dynamic_cast<Foo *>(baseVector.back().get())->value()));
for (auto &base : baseVector)
base->execute();
return 0;
}
然而,dynamic_cast
对我来说很臭(我知道我也可以使用static_cast
,但我想这并没有好到哪里去)。避免dynamic_cast
的另一种选择是将Foo
类更改为类似
class Foo: public Base {
public:
Foo() : value_(new int()) {}
void execute() override {
// Foo-specific implementation of execute(), may change value_
*value_ = 2;
}
const int & value() const {
return *value_;
}
private:
std::unique_ptr<int> value_;
};
然后做
int main() {
// Collection of base objects, possibly inside another object
std::vector<std::unique_ptr<Base>> baseVector;
auto foo = make_unique<Foo>();
auto *fooPtr = foo.get();
baseVector.emplace_back(std::move(foo));
baseVector.emplace_back(make_unique<Bar>(fooPtr->value()));
for (auto &base : baseVector)
base->execute();
return 0;
}
但这似乎也不是很优雅。如何以适当的方式处理此类情况?
我会用一种更通俗易懂的方式写它:
struct Base { virtual ~Base() = default; /* ...*/ };
struct Foo : Base { int x_; int & value() { return x_; /* ...*/ };
struct Bar : Base { int & r_; Bar(int & r) : r_(r) {} /* ...*/ };
auto foo = std::make_unique<Foo>();
auto bar = std::make_unique<Bar>(foo->value());
v.push_back(std::move(foo));
v.push_back(std::move(bar));
仅仅因为emplace_back
的存在并不意味着你必须把它用于所有事情!
相关文章:
- C++-模板嵌套类的引用初始化无效
- 在这个函数中是有缺陷的,因为取消引用 null 是无效的,所以我想更改代码
- 从 BubbleSort* 类型的右值初始化 'AssortedSorter&' 类型的非常量引用无效"
- 为什么在引用指针时将 const 放在 & 符号的左侧有效,而在右侧则无效?
- 为什么通过 vector<reference_wrapper> 的元素删除引用的值<T>不会使向量无效?
- 具有引用返回类型的重写方法上的协变返回类型无效
- 为什么我总是收到此错误:从类型为"农场动物"的右值初始化类型的非常量引用无效|
- 对全局变量的非常量引用的初始化无效
- 为什么右值不能绑定到非常量左值引用,除了写入临时无效的事实?
- 对类型为 std::_Bit_rerefence& 的非常量引用的初始化无效
- 模板流运算符重载错误:引用初始化无效,与basic_istream和basic_ifstream之间的差异有关
- 成本字符*类型的非常量引用的无效初始化,并且来自常量字符*类型的临时引用
- 对唯一 ptr 无效读取的引用向量
- 中毒的无效引用和短路表达评估错误或UB
- 返回无效引用
- 在基于范围的 for 循环中获取无效引用
- 通过重新解释强制转换创建无效引用
- 子弹物理由于无效引用而崩溃
- 对多态对象成员的无效引用
- 基于jobobject调用Java方法失败(无效引用?)