как создать конструктор перемещения, который принимает строковый литерал const char*

Я хочу создать конструктор перемещения, который принимает строковый литерал, а затем переместить эту строку c в указатель члена. Лучшее решение, которое я мог бы написать, это дать предупреждение: устарело преобразование строковой константы в 'char*' [-Wwrite-strings] CTextBlock cctb("move(H)"); ^ код:

#include <iostream>
using namespace std;

class CTextBlock
{
public:
    CTextBlock(char* &&text)//move constructor
    {
        pText = text;
    }
private:
    char *pText;
};
int main()
{
    CTextBlock cctb("move(H)"); //WARNING
    return 0;
}

person Obay Abd-Algader    schedule 11.04.2015    source источник
comment
Это не конструктор перемещения. Это обычный конвертирующий конструктор.   -  person chris    schedule 12.04.2015
comment
как? , требуется char* &&   -  person Obay Abd-Algader    schedule 12.04.2015
comment
Конструктор перемещения займет CTextBlock&&. Я вообще не вижу смысла в ссылке на rvalue. У вас есть проблема с попыткой указать на постоянные данные с помощью указателя на непостоянные данные.   -  person chris    schedule 12.04.2015
comment
Попробуйте template<size_t N>CTextBlock(char const(&&text)[N]) и используйте std::move для литерала "". Не уверен, что это сработает, но попробуйте. О, и сделайте член char const*: "literal" строк постоянными данными.   -  person Yakk - Adam Nevraumont    schedule 12.04.2015
comment
Вы имеете в виду, что только потому, что он принимает ссылку rvalue, он не делает его конструктором перемещения?   -  person Obay Abd-Algader    schedule 12.04.2015
comment
@ObayAbd-Algader: не каждый конструктор, который принимает T&&, является конструктором перемещения. Это только в том случае, когда это конструктор of T!!   -  person Lightness Races in Orbit    schedule 12.04.2015
comment
что такое template‹size_t N›CTextBlock(char const(&&text)[N])?   -  person Obay Abd-Algader    schedule 12.04.2015
comment
хорошо, это сработало @chris, но я не хочу, чтобы участник указывал на const   -  person Obay Abd-Algader    schedule 12.04.2015
comment
Это конструктор, принимающий ссылку rvalue на массив N объектов типа char const. Например, строковый литерал имеет такой тип. Почему передается ссылка на rvalue такой ссылки, я не знаю, и я действительно не думаю, что это работает: результат std::move("foo") should be a const` rvalue такого массива...   -  person Dietmar Kühl    schedule 12.04.2015
comment
Если вы не хотите, чтобы член был char const*, вам, вероятно, потребуется скопировать строковый литерал, поскольку символы в строковом литерале оказываются const.   -  person Dietmar Kühl    schedule 12.04.2015


Ответы (3)


Во-первых, строковые литералы имеют тип char const[N] (для подходящей константы N). Этот массив можно присвоить char const*, и в этом случае он превратится в указатель на первый элемент. Его нельзя преобразовать в char*. До C++11 преобразование в char* разрешалось иметь дело с существующим кодом, который не был const-правильным (например, потому что он начинался как код C до того, как C получил const). Это преобразование было удалено для C++11.

Вопрос в том, чего вы на самом деле пытаетесь достичь: строковые литералы неизменяемы и сохраняются в течение всего времени жизни программы. Вы можете просто хранить столько указателей на них, сколько хотите, и нет смысла перемещать указатели, поскольку их копировать совсем дешево.

В своем вопросе вы указываете, что хотите создать конструктор перемещения, но конструкторы перемещения берут ссылку rvalue на класс, для которого они предназначены, например, это будет конструктор перемещения для вашего класса:

CTextBlock::CTextBlock(CTextBlock&& other)
    : pText(other.pText) {
    other.pText = 0;
}

(ваш класс не показывает никакой семантики владения для указателя pText, и в этом случае конструкция перемещения не имеет большого смысла; приведенный выше код предполагает, что существует некоторая семантика владения и что нулевой указатель указывает, что объект не владеет что-либо).

Тот факт, что аргумент ограничен ссылкой на rvalue, не означает, что функция является конструктором перемещения. Все, что это подразумевает, это то, что аргумент является значением r, и можно разумно предположить, что его текущее представление не нужно сохранять. Строковый литерал выглядит как rvalue, потому что строковый литерал преобразуется в [временный] указатель на начало массива.

person Dietmar Kühl    schedule 11.04.2015

Конструктор, который достаточно близок к разрешению только литералов, может быть реализован в виде шаблона:

#include <cstddef>
#include <assert>

struct X
{
    char const * str;
    std::size_t len;

    template <std::size_t N>
    X(char const (&a)[N]) : str(a), len(N - 1)
    {
        assert(a[len] == '\0');   // true for string literals
    }
};

Однако это не является надежным, поскольку оно также будет связываться с именованными массивами символов, а вычисление длины будет сомнительным, если ваша строка также содержит нулевые значения. Но если вы пытаетесь избежать случайного использования динамических значений (например, в алгоритме, который строит строки из выражений и литеральных строк), это довольно полезно.

person Kerrek SB    schedule 11.04.2015
comment
=delete для не-const улучшает это. - person Yakk - Adam Nevraumont; 12.04.2015

Строковый литерал — это const char *. Это верно независимо от того, используется ли оно как lvalue или rvalue.

Если вы снова просматриваете свой код, вы, следовательно, пытаетесь сохранить const char * в char *, и именно отсюда исходит ваша диагностика компилятора. Ваш конструктор перемещения принимает ссылку rvalue на char *, а не на const char *. Измените его на const char * и измените член класса pText на const char *, и то, что вы пытаетесь сделать, должно работать.

person Sam Varshavchik    schedule 11.04.2015
comment
Строковый литерал — это const char * Нет, это не так. - person Lightness Races in Orbit; 12.04.2015