Reputation: 9292
I am working on an existing large project which basically:
Currently, children are stored using smart pointers, mostly to avoid deep copies when building the graph from file read and during user edition of the graph.
As the smart pointers (std::shared_ptr) do not propagate constness, I have the following options:
I know that using smart pointers only to avoid deep copies during tree manipulation is not the nice way to implement this at the age of c++11 and move semantics. Rewriting all the code with move semantics might be done one day, but this represents quite a large work.
What would be, in your opinion, the nicest way to implement that pattern, without rewriting all with move semantics? I have thought of wrapping std::shared_ptr to propagate constness, are there other ideas?
Thanks!
Upvotes: 1
Views: 675
Reputation: 15334
I would go with option 3 but store the children in private member variables in a base class or composed object.
Only allow access to the children via getters that enforce const correctness.
The const getter returning a raw pointer-to-const. The non-const getter returning a raw pointer or shared pointer.
Something like:
#include <iostream>
#include <memory>
#include <vector>
template<class Child>
class Parent {
private:
std::vector<std::unique_ptr<Child>> children_;
protected:
~Parent() = default;
public:
const Child* getChild(size_t child_number) const {
return children_.at(child_number).get();
}
Child* getChild(size_t child_number) {
return children_.at(child_number).get();
}
size_t getNumberOfChildren() const {
return children_.size();
}
void addChild(std::unique_ptr<Child> child) {
children_.emplace_back(std::move(child));
}
};
struct Node : Parent<Node> {
private:
std::string name_;
public:
Node(std::string name) : name_(std::move(name)) {}
void print() const { std::cout << "Node: " << name_ << "\n";}
void setName(const std::string& name) { name_ = name; }
void wrong() const {
//children_[0]->setName("Wrong"); // Not allowed
//getChild(0)->setName("Wrong"); // Not allowed
}
};
void printRecursive(const Node* node) {
if (node) {
node->print();
for (size_t i=0; i!=node->getNumberOfChildren(); ++i)
printRecursive(node->getChild(i));
}
}
int main() {
// Initialization
Node root("Root");
root.addChild(std::make_unique<Node>("Child 1"));
root.addChild(std::make_unique<Node>("Child 2"));
// "Computation" with pointer-to-const
const Node* root_ptr = &root;
printRecursive(root_ptr);
}
Live demo - using composition.
I've used unique_ptr
instead of shared_ptr
in my example because I can but you may have a good reason to use shared_ptr
.
Upvotes: 0