colorname
@colorname

Почему не вызывается конструктор копирования при инициализации переменной другим объектом?

Понимаю что исходный код достаточно большой, но все же, надеюсь кто то да подскажет.
Пытаюсь разобраться с кодом из книги Lippman С++ Primer, конец 15 главы.
Возможно я что то неправильно понимаю, но почему в `main` в строке:
Query query = Query("she") & Query("is");
копирующий конструктор Query вызывается всего 2 раза при вызове конструктора BinaryQuery, когда происходит инициализация lhs и rhs, но не вызывается когда собственно инициализируется переменная query в функции main?
Собственно и не могу понять каким образом инициализируется эта переменная если не при помощи копирующего конструктора.

Как я понял, алгоритм выполнения следующий:
1. Создается файловый поток
2. Создается объект класса `TextQuery`
3. Вызывается конструктор `Query(string)` с аргументом `"she"` (внутри вызывается `WordQuery(string)`)
4. Вызывается конструктор `Query(string)` с аргументом `"is"` (внутри вызывается `WordQuery(string)`)
5. Вызывается оператор `&` с двумя аргументами
6. Вызывается конструктор `AndQuery` в который передаются оба операнда
7. Вызывается конструктор `BinaryQuery` в котором происходит инициализация lhs и rhs с помощью копирующего конструктор `Query`
8. Далее вызывается конструктор `Query` с параметром `shared_ptr`, после чего q ссылается на AndQuery объект
9. И вот тут по моему должен вызываться копирующий конструктор `Query` чтобы произошла инициализация переменной `query` в функции `main`, но почему то этого не происходит...

Исходный код:
spoiler
using namespace std;

class QueryResult
{
public:
	using line_no = vector<string>::size_type;
	QueryResult(string sw, shared_ptr<set<line_no>> ln, shared_ptr<vector<string>> ft) : sought_word(sw), lines_numbers(ln), file_text(ft) {}
	auto begin() const { return lines_numbers->begin(); }
	auto end() const { return lines_numbers->end(); }
	auto get_file() const { return file_text; }
private:
	string sought_word;
	shared_ptr<set<line_no>> lines_numbers;
	shared_ptr<vector<string>> file_text;
};

class TextQuery
{
public:
	using line_no = vector<string>::size_type;
	TextQuery(ifstream& is) : file_text(new vector<string>)
	{
		string line;
		while (getline(is, line))
		{
			file_text->push_back(line);
			istringstream line_stream(line);
			string word;
			while (line_stream >> word)
			{
				auto& lines_numbers = words_map[word];
				if (!lines_numbers) lines_numbers.reset(new set<line_no>);
				lines_numbers->insert(file_text->size() - 1);
			}
		}
	}
	QueryResult query(const string& sought_word) const
	{
		static shared_ptr<set<line_no>> no_data(new set<line_no>);
		auto loc = words_map.find(sought_word);
		if (loc == words_map.end()) return QueryResult(sought_word, no_data, file_text);
		else return QueryResult(sought_word, loc->second, file_text);
	}
private:
	shared_ptr<vector<string>> file_text;
	map<string, shared_ptr<set<line_no>>> words_map;
};

class QueryBase
{
	friend class Query;
protected:
	using line_no = TextQuery::line_no;
	virtual ~QueryBase() = default;
private:
	virtual QueryResult eval(const TextQuery&) const = 0;
	virtual string rep() const = 0;
};

class Query
{
	friend Query operator~(const Query&);
	friend Query operator|(const Query&, const Query&);
	friend Query operator&(const Query&, const Query&);
	friend ostream& operator<<(ostream&, const Query&);
public:
	Query(const string&);
	Query(const Query& query)
	{
		cout << "Here..." << endl;
		q = query.q;
	}
	QueryResult eval(const TextQuery& t) const { return q->eval(t); }
	string rep() const { return q->rep(); }
private:
	Query(shared_ptr<QueryBase> query) : q(query) {}
	shared_ptr<QueryBase> q;
};

ostream& operator<<(ostream& os, const Query& query)
{
	return os << query.rep();
}

class WordQuery : public QueryBase
{
	friend class Query;
private:
	WordQuery(const string& s) : query_word(s) {}
	QueryResult eval(const TextQuery& t) const { return t.query(query_word); }
	string rep() const { return query_word; }
	string query_word;
};

inline Query::Query(const string& s) : q(new WordQuery(s)) {}

class BinaryQuery : public QueryBase
{
protected:
	BinaryQuery(const Query& l, const Query& r, string s) : lhs(l), rhs(r), op_sym(s) {}
	string rep() const { return "(" + lhs.rep() + " " + op_sym + " " + rhs.rep() + ")"; }
	Query lhs;
	Query rhs;
	string op_sym;
};

class AndQuery : public BinaryQuery
{
	friend Query operator&(const Query&, const Query&);
	AndQuery(const Query& left, const Query& right) : BinaryQuery(left, right, "&") {}
	QueryResult eval(const TextQuery& text) const
	{
		auto left = lhs.eval(text);
		auto right = rhs.eval(text);
		auto ret_lines = make_shared<set<line_no>>();
		set_intersection(left.begin(), left.end(), right.begin(), right.end(), inserter(*ret_lines, ret_lines->begin()));
		return QueryResult(rep(), ret_lines, left.get_file());
	}
};

inline Query operator&(const Query& lhs, const Query& rhs)
{
	auto temp = shared_ptr<QueryBase>(new AndQuery(lhs, rhs));
	return Query(temp);
}

int main()
{
	ifstream file("./file.txt");
	TextQuery text_query(file);
	Query query = Query("she") & Query("is"); // ???????????????????????
	print(cout, query.eval(text_query));

	return 0;
}
  • Вопрос задан
  • 68 просмотров
Решения вопроса 1
wataru
@wataru Куратор тега C++
Разработчик на С++, экс-олимпиадник.
Тут сработало copy elision.

operator& не создает никакого временного Query, а работает сразу с Query в месте его вызова. Поэтому конструктор в пункте 8 создает уже результат.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы