Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.117.183.150] |
|
Сообщ.
#1
,
|
|
|
#include <iostream> #include <string> void test(const std::string& str) { std::cout << str; } int main() { test("Hello my dear friend!\n"); } Что происходит? Создаётся временный объект const std::string, конструктор которого принимает (и копирует в себя) const char*, вызывается функция test, затем объект уничтожается. Много лишних действий. Можно ли сделать так, чтобы в EXE-шнике изначально хранился объект std::string, а не создавался перед вызовом функции? p.s. В идеале – C++11, но если вариантов нет, рассмотрю что есть. p.p.s. Интересен также вариант без создания промежуточных констант, если такое возможно, потому что, понятное, дело, можно сделать const std::string text = "Hello my dear friend!\n"; и подставлять её, но это неинтересно. Да и всё равно объект создаётся динамически. |
Сообщ.
#2
,
|
|
|
Цитата Jin X @ Почти. Создаётся временный std::string (r-value), который успешно биндится на константную l-value ссылку, и чьё время жизни заканчивается по достижению ;, т.е. по возврату из test().Что происходит? ... Цитата Jin X @ Нет. Объекты с нетривиальными конструкторами не могут быть созданы иначе, нежели в run-time, кроме как constexpr. Конкретно std::string требует наличия хипа для связи указателей с хранилищем dynamic storage, поэтому не может иметь constexpr конструкторов. Можно ли сделать так, чтобы в EXE-шнике изначально хранился объект std::string, а не создавался перед вызовом функции? |
Сообщ.
#3
,
|
|
|
Qraizer, я тут делаю одну штуку, в которой путём экспериментов мне удалось сделать функцию constexpr std::string. Прога компилится в GCC, VS и ICC, а вот Clang на неё ругается.
Правда, когда я пытаюсь выдернуть этот кусок отдельно, то ничего не получается, компилеры ругаются как раз на constexpr std::string. Можешь глянуть и объяснить это явление? Ищи static constexpr std::string get_default_suffix_text() p.s. Эта штука не доделана, поэтому выкладываю под названием temp [прикреплённый файл удалён] Добавлено Навели на мысль заюзать string_view. Выглядите куда веселее: https://godbolt.org/z/XAm-S- Жаль только, что C++17. |
Сообщ.
#4
,
|
|
|
Цитата Jin X @ constexpr для функций означает лишь, что они могут использоваться в константных выражениях. Исполнение их в компайл-тайм может оказаться невозможным, но компилятор может сделать всё возможное, чтобы всё возможное выполнить при компиляции. Ошибкой будет считаться лишь невозможность породить результат т.о., чтобы в используемом контексте его можно было бы использовать. Например, если результат constexpr функции, возвращающей int, будет использовать как указание размера массива в его определении, ибо Стандарт обязывает указывать там только константные выражения, вычислимые в компайл-тайм. Так что формально в твоём случае компилятор может выполнить всю работу get_default_suffix_text(), но отложить создание результирующего объекта до ран-тайм, т.к. контекст не обязывает его предоставить результат ранее ран-тайма. Насколько мне известно, но это неточно, в C++20 потребовали, чтобы constexpr стало обязательной инструкцией компилятору. Вероятно поэтому clang и ругается. Однако C++20 пока ещё не ратифицирован. Более того, в описании constexpr среди прочего указано, что возвращаемое значение должно быть literal type, к каковым std::string явно не относится, т.к. literal type должен иметь (по меньшей мере, но не ограничиваясь) тривиальный деструктор.Можешь глянуть и объяснить это явление? Цитата Jin X @ std::string_view не хранит информации, он лишь ссылается на неё, хранимую ещё где-то. В твоём случае строковый литерал вполне подходит, т.к. имеет время жизни до конца программы (static storage duration). Но в общем случае это противоречивый класс: являясь по сути ссылочным типом, легко впоследствии может оказаться указываемым в ничто, если исходный объект будет разрушен раньше времени. Зато string_view позволяет работать с собой как с constexpr. Навели на мысль заюзать string_view. |
Сообщ.
#5
,
|
|
|
Цитата Jin X @ можно сделать const std::string text = "Hello my dear friend!\n"; и подставлять её, но это неинтересно. Да и всё равно объект создаётся динамически. А можно сделать static const std::string и объект будет создаваться только 1 раз (если цель в экономии тактов процессора). |
Сообщ.
#6
,
|
|
|
Спасибо, Qraizer за разъяснения
Да, я уже понял, что Clang более чётко следует стандартам. Цитата Qraizer @ Да, я понимаю, что при передаче string это будет просто size() и c_str(), а при строковом литерале — его длина и const char* со всеми вытекающими. Так-то, и при передаче const string& значение параметра может поменяться, если исходный объект будет изменён раньше времени (а если это будет динамически созданный объект, то так же может указывать в никуда). И такую строку тоже нужно копировать во избежание этого.являясь по сути ссылочным типом, легко впоследствии может оказаться указываемым в ничто, если исходный объект будет разрушен раньше времени. shm, это я понимаю. Но я думал, что можно в копмайл-тайм создать его, ан нет. Просто, если функция вызывается много раз с разными константными строками, всё равно их все придётся создавать динамически. И даже копировать. Не то, чтоб я прям хотел сэкономить такты, просто бессмысленность вот этого копирования (а еще ведь надо память выделить и освободить) и пр. смутила . Что-то компилятор, конечно, соптимизирует, но это все implementation defined, как говорится. |
Сообщ.
#8
,
|
|
|
Цитата shm @ Ну да, любопытно. Но заморочи много. Действительно, не всегда это надо.Тема раскрыта, например, тут. Но я думаю, что все это преждевременная оптимизация. Цитата Qraizer @ Инструкцией к чему?Насколько мне известно, но это неточно, в C++20 потребовали, чтобы constexpr стало обязательной инструкцией компилятору. Для обязательного выполнения именно в compile time вводится consteval. Добавлено Кстати, что интересно, код со string_view более оптимальный даже, чем с char*, ибо там уже есть длина строки (странно только, что этот код не инлайнится автоматом): https://godbolt.org/z/oJokK8 |
Сообщ.
#9
,
|
|
|
Цитата Jin X @ Можно. А как Вы собиратесь привязать его к конкретному вызову конкретной функции. Хорошо, когда функция простейшая и вызывается из одного потока. Тогда до завершения одной её ветви следующий вызов не поступит. А если приложение многопоточное? Многопоточность есть многозадачность не ситемы, а отдельно взятой исполняемой под системой программы. Поток прервался посреди функции, другой поток вызвал её ещё раз с другим фактическим параметром, получили две ветви одной функции, каждая вызвана из своего потока, потом первая ветвь продолжила выполняться, а строка уже другая. Или функция рекурсивна. Такая функция, не завершившись, вызывает себя с другим фактическим параметром. Завершаясь же, такая функция возвращает управление себе. Вызвала функция себя, строка изменилась, потом функция заврешилась и вернула управление той себе, которая вызвана не из себя, а из мэйн, там строка должна быть из первого вызова, а будет из второго. К тому же копирование и удаление даже в самом кривом исполнении занимают меньше тактов, чем оптимальное копирование. Если только это действительно копирование, а не асоциирование. То есть если после Можно ли сделать так, чтобы в EXE-шнике изначально хранился объект std::string, а не создавался перед вызовом функции? char s[]="какой-то текст"; t(s); Добавлено Цитата Qraizer @ В рантайм? Или перед самым вызовом конкретной функции? Вот в чём вопрос. Заранее создать можно, статически нельзя. Нет. Объекты с нетривиальными конструкторами не могут быть созданы иначе, нежели в run-time, кроме как constexpr. |
Сообщ.
#10
,
|
|
|
Цитата Ирокез @ Вопрос как раз в создании статически.Заранее создать можно, статически нельзя. Строка константная, изменена не будет, поэтому проблем с многопоточностью нет. |
Сообщ.
#11
,
|
|
|
Цитата Jin X @ Нельзя. Да и зачем? Вы ж разменяете быстродействие процессора на вращение диска и можете даже потерять.Вопрос как раз в создании статически. Цитата Jin X @ А компилятор об этом знает? Даже если он способен проанализировать весь исходник, то и тогда не сможет сделать вывод о том, что других строк не появится. Может строка ровно одна пока? Компилятор этого исключить не может, а авторы линкера и кодогенератора вообще не в курсе количества строк. И если строка одна, то её так и так придётся сначала создать, а потом удалить. Вот если строк миллиард, но никакие две не нужны одновременно, тогда можно, разместив их в одном и том же объекте, а меняя только его значение, сэкономить на девятьсот девяносто миллионов девятьсот девяносто девять тысяч девятьсот девяносто девяти вызовах конструктора и таком же количестве вызовов деструктора. Да и то надо ещё постараться, чтоб те же вызовы не «влезли через окно». Да и даже если бы можно было бы сэкономить единственный вызов конструктора, пользователь этого не заметит даже если он вообще не из нашей метагалактики. Строка константная, изменена не будет, поэтому проблем с многопоточностью нет. |
Сообщ.
#12
,
|
|
|
Цитата Jin X @ Создай статически, объяви константной. Если в библиотеке предусмотрено константное поведение строк, от части операций удастся избавиться. Однако перестанут вызываться функции, в которые эта строка передаётся по неконстантной ссылке. Так что константной объявить строку возможно и не получится (зато узнаешь, как часто эта строка передаётся в функции, которые её содержимое, по мнению компилятора, могут изменить, если не сейчас, то когда-нибудь в будущем, если будут переписаны). Строка константная, изменена не будет |