Я просматривал свой код и возился с ним, но не могу понять, почему я получаю не ожидаемый результат, а вместо этого случайные символы.
Ожидаемый результат: JoeUPSReminderPick up your package! 54,23
Я получаю <, но все, что после этого, - тарабарщина. Любая помощь будет оценена по достоинству.
#include <cstddef> // for std::size_t
#include <iostream>
#include <memory>
#include <ostream>
#include <string>
#include <utility> // for std::move, std::forward
#include <vector>
class xml_node_base
{
public:
virtual ~xml_node_base() = default;
void output(std::ostream& os) const
{
do_output_open(os);
do_output_body(os);
do_output_close(os);
}
protected:
virtual void do_output_open(std::ostream& os) const = 0; // abstract
virtual void do_output_body(std::ostream&) const { } // not abstract
virtual void do_output_close(std::ostream& os) const = 0; // abstract
};
using xml_node_base_t = std::shared_ptr<xml_node_base>;
using xml_node_bases_t = std::vector<xml_node_base_t>;
template <typename T, typename... Args>
inline xml_node_base_t make_xml_node(Args&&... args)
{
return std::make_shared<T>(std::forward<Args>(args)...);
}
class xml_node: virtual public xml_node_base
{
private:
std::string const& node_name;
public:
xml_node() = delete;
xml_node(std::string const& name) : node_name(name)
{
};
protected:
void do_output_open(std::ostream& os) const override
{
os << "<" << node_name << ">";
};
void do_output_close(std::ostream& os) const override
{
os << "</" << node_name << ">";
};
};
class xml_node_with_children: public xml_node
{
private:
xml_node_bases_t children_;
public:
xml_node_with_children() = delete;
xml_node_with_children(std::string const& name) : xml_node(name)
{
};
xml_node_with_children(std::string const& name, std::size_t reserve) : xml_node_with_children(name)
{
children_.reserve(reserve);
};
xml_node_with_children(std::string const& name, xml_node_bases_t children) : xml_node(name), children_(std::move(children))
{
};
protected:
auto& children() { return children_; };
auto const& children() const { return children_; };
void do_output_body(std::ostream& os) const
{
for (auto const& c : children_)
{
c -> output(os);
}
};
};
template <typename T>
class value_node : public xml_node
{
private:
T datum;
protected:
void do_output_body(std::ostream& os) const
{
os << datum;
}
public:
value_node(std::string const& name, T const& v) : xml_node(name), datum(v)
{
}
};
class note : public xml_node_with_children
{
public:
note() = delete;
note(std::string const& to, std::string const& from, std::string const& subject, std::string const& message) : xml_node_with_children("note", 4)
{
children().push_back(make_xml_node<value_node<std::string>>("to",to));
children().push_back(make_xml_node<value_node<std::string>>("from",from));
children().push_back(make_xml_node<value_node<std::string>>("subject",subject));
children().push_back(make_xml_node<value_node<std::string>>("message",message));
}
};
class root : protected xml_node_with_children
{
public:
using xml_node_with_children::xml_node_with_children;
using xml_node_with_children::output;
using xml_node_with_children::children;
};
std::ostream& operator<<(std::ostream& os, root const& r)
{
r.output(os);
return os;
}
int main()
{
root notes{"notes"};
notes.children().push_back(
make_xml_node<note>("Joe", "UPS", "Reminder", "Pick up your package!")
);
notes.children().push_back(
make_xml_node<value_node<double>>("priority",54.23)
);
std::cout << notes << '\n';
}
Я думаю, что проблема может быть связана с циклом for в строке 90, так как я не очень хорошо знаком с оператором ->.
std::string const& node_name;
xml_node(std::string const& name) : node_name(name)
Этот член класса является ссылкой, и конструктор инициализирует его из ссылки, которая передается конструктору в качестве параметра.
Давайте проследим все в обратном порядке и посмотрим, откуда изначально берется параметр для конструктора. Вот один пример:
children().push_back(make_xml_node<value_node<std::string>>("to",to));
Параметр представляет собой литеральную строку, "to"
.
C++ очень известен и очень хорошо известен тем, что дает всем возможность выстрелить себе в ногу, если это то, что они действительно хотят сделать, поэтому:
Создается временный объект std::string
.
Ссылка на этот объект передается в качестве параметра через несколько луковичных уровней конструкторов, как у слона.
Ссылка на этот объект сохраняется в члене базового класса.
После завершения всех конструкторов и завершения выполнения этого оператора временный std::string
объект, которому принадлежит этот "to"
, уничтожается.
Экземпляр класса теперь имеет ссылку на уничтоженный объект в своем node_name
.
Это повторяется для всех других объектов в показанном коде, построенных таким образом.
Ты только что выстрелил себе в ногу.
включение дезинфицирующего средства адресов может помочь вам в отладке: godbolt.org/z/6san37xq3