【发布时间】:2015-11-05 19:02:33
【问题描述】:
我做了什么:我最近开始编写一个多线程的生产者-消费者式队列。最初,我使用智能指针,但最终将它们全部更改为原始指针并手动管理它们的生命周期和内存管理(如果有兴趣,请在最后编写代码)。
我在寻找什么:支持或反对这个猜想的论据:
继承不能和共享指针在同一个房间里,就像原始指针和引用对象一样。
我的推理:
Base 和 Derived 对象是协变的。原始指针(Base* 和 Derived*)也是如此。共享指针(shared_ptr<Base> 和 shared_ptr<Derived>)不是。
程序员必须使用dynamic_pointer_cast 进行许多概念上不必要的向下转换,这使代码变得丑陋并且在编译时和运行时有些昂贵。
这让我想知道在面向对象的设计中是否应该避免共享指针,因为它们的好处并没有超过它们的费用和令人头疼的问题。
我修改前的代码(为了可读性,多线程省略了):
typedef shared_ptr<Animal> animal_ptr;
typedef shared_ptr<Dog> dog_ptr;
class Buffer {
private:
mutex mu_;
condition_variable cond_;
deque<shared_ptr<Animal> > buffer_;
public:
void add(shared_ptr<Animal> req) {
std::unique_lock<std::mutex> locker(mu_);
cond_.wait(locker, [this](){return buffer_.size() < size_;});
buffer_.push_back(req);
locker.unlock();
cond_.notify_all();
}
shared_ptr<Animal> remove() {
unique_lock<mutex> locker(mu_);
cond_.wait(locker, [this](){return buffer_.size() > 0;});
shared_ptr<Animal> back = buffer_.back();
buffer_.pop_back();
locker.unlock();
cond_.notify_all();
}
};
int main() {
Buffer buffer;
animal_ptr bPtr1 (new Animal()); // buffer.add() works just fine
dog_ptr dPtr1 (new Dog()); // EDIT: works fine too.
animal_ptr dptr2 (new Dog()); // EDIT: it's okay
...
buffer.remove(); // returns a base class object, requires downcasting to access derived members
}
编辑以获得更多说明,以及为什么共享指针对继承的处理与原始指针不同:
void func1(shared_ptr<Animal> ptr);
void func2(Animal* ptr);
...
Dog* rawPtr = new Dog();
func1(dPtr1); // is not possible, requires upcasting
func2(rawPtr); // is ok.
【问题讨论】:
-
returns error到底是什么意思? coliru.stacked-crooked.com/a/518ccd53897ea6b3 -
我的第二个问题是
requires upcasting before buffer.add()是什么意思?请参阅我之前的代码示例。 -
@AndyG 您的第二条评论也是有效的。我的错误是我忘记在我的简单代码中继承
class Animal,因此所有的误解。 -
我还是不明白有必要向上和向下...
-
@VermillionAzure 我解释了:调用 buffer.remove() 会给你一个 shared_ptr
,它不会自动转换为 shahred_ptr ,需要使用 dynamic_pointer_cast 进行运行时检查
标签: c++ c++11 inheritance casting shared-ptr