Передать по ссылке, неявно вызывая копию ctor для несовместимого аргумента? - PullRequest
0 голосов
/ 03 декабря 2018

Я работаю со следующим устаревшим шаблоном кода для отладочных выходов.Я понимаю, что это не самый эффективный способ печати отладочных сообщений, но мой вопрос касается чего-то более фундаментального.Это кажется основным вопросом, но это поставило под сомнение мое понимание того, как параметры функции, указанные как проходные по постоянной ссылке, интерпретируются компилятором.

Шаблон для сообщений отладки в унаследованном коде представлен ниже:

#include <iostream>
#include <cctype>
#include <cstring>
#include <stdio.h>



void debugMsg(const std::string& testStringRef){
    printf("%s\n", testStringRef.c_str());
}

int main() {

#if defined(DEBUG_MSG_OUT)
    char debug_message[512];
    snprintf(debug_message,512, "TESTING 12345678910!");
    debugMsg(debug_message);
#endif
    return 0;
}

Теперь, прежде чем этот пример привлек мое внимание сегодня, я бы сказал, что он не должен компилироваться, поскольку debugMsg принимает проходпо константной строковой ссылке и вызывается с помощью char [].Но он компилирует и выводит ожидаемую строку при запуске.

Это поставило под сомнение мое понимание параметров передачи по ссылочной функции (я понимаю, что это базовые знания C ++, но для меня это было новым).Я думал, что одно из главных преимуществ параметров справочной функции заключается в том, чтобы избежать создания копирования, которое происходит при передаче по значению.Я бы подумал, что неявные преобразования аргументов при передаче по ссылочным параметрам не будут разрешены, и вместо этого будет ошибка компиляции.Но мне кажется, что временный строковый объект все еще создается, хотя debugMsg является функцией передачи по ссылке.

Я смотрел на разборку этого кода и не вижу вызова конструктора копирования std :: string.Может кто-нибудь прояснить, что здесь происходит с деталями низкого уровня?Если на самом деле char [] неявно преобразуется в std :: string, а затем этот объект передается в debugMsg (), почему это допускается в C ++ для конкретного прохода ссылочными функциями?

Disassembly debugMsg

Ответы [ 2 ]

0 голосов
/ 03 декабря 2018

Неявные преобразования являются нормальной частью привязки ссылок.Поскольку строковый литерал не является std::string, выполняется вызов конструктора преобразования basic_string( const CharT* s, const Allocator& alloc = Allocator() ).Этот результирующий временный объект привязывается к ссылке до конца полного выражения.Естественно, не было бы вызова конструктора копирования, поскольку мы имеем дело со ссылками.

0 голосов
/ 03 декабря 2018

Это нормально.Если есть неявный допустимый конструктор, он будет использоваться как преобразование.Создание строки из строкового литерала использует конструктор char const *.(Вот почему вы не видите конструктор копирования - он вызывается только если мы копируем std :: string, но в этом случае мы создаем его из литерала, поэтому используется другой конструктор.)

Ваш вопрос сводится к следующему: «Я удивлен, что временное значение (rvalue) может связываться со ссылкой lvalue на const».Это было верно для c ++ до того, как оно было стандартизировано в 1998 году. Однако ожидаемая ошибка действительно существует, если вы попытаетесь привязать временную ссылку к неконстантной lvalue ссылке.Идея в том, что если это модифицируемая ссылка lvalue, функция изменит свое значение.Поскольку запись во временное хранилище почти всегда является ошибкой, и для этого не было веских аргументов, это было запрещено.Но привязка временного к ссылке на константное значение допускается, потому что он используется только как вход только для чтения, а временный длится по крайней мере столько, сколько время жизни ссылки lvalue, которая связывается с ним.Это полезно и безопасно.

...