как использовать memcpy с unique_ptr - PullRequest
0 голосов
/ 04 февраля 2020

Я пытался выучить умный указатель, когда натолкнулся на это.

{ //Example 1
    //String to be copied
    std::string strHello = "HelloWorld1";
    int size = strHello.length();

    //Creating Ptr using make_unique
    std::unique_ptr<char[]> pstrText;
    pstrText = make_unique<char[]>(size + 1); // Allocating +1 for \0

    //Copying values to the new pointer
    int r = memcpy_s(pstrText.get(), size + 1, strHello.c_str(), size);

    //Printing
    std::cout << pstrText.get() << std::endl;
}

{ //Example 2
    //String to be copied
    std::string strHello = "HelloWorld2";
    int size = strHello.length();

    //Creating Ptr using make_unique
    std::unique_ptr<char[]> pstrText;
    pstrText = make_unique<char[]>(size);

    //Copying values to the new pointer
    int r = memcpy_s(pstrText.get(), size, strHello.c_str(), size);

    //Printing
    std::cout << pstrText.get() << std::endl;
}
{//Example 3

    //String to be copied
    std::string strHello = "HelloWorld3";
    int size = strHello.length();

    //Creating Ptr using make_unique
    std::unique_ptr<char[]> pstrText;
    pstrText = make_unique<char[]>(size + 1); //Allocating + 1

    //Copying values to the new pointer
    int r = memcpy_s(pstrText.get(), size, strHello.c_str(), size);

    //Printing
    std::cout << pstrText.get() << std::endl;
}

{//Example 4

    //String to be copied
    std::string strHello = "HelloWorld4";
    int size = strHello.length();

    //Creating Ptr using make_unique
    std::unique_ptr<char[]> pstrText;
    pstrText = make_unique<char[]>(size);

    //Copying values to the new pointer
    int r = memcpy_s(pstrText.get(), size + 1, strHello.c_str(), size); 

    //Printing
    std::cout << pstrText.get() << std::endl;
}

Вывод следующий: VS 2013 Debug (Win32):

HelloWorld1
HelloWorld2²²²²½½½½½½½½■
HelloWorld3
HelloWorld4²²²²½½½½½½½½■
  1. Если Пример 1 верен, почему Пример 3 также дает правильный вывод?
  2. Что означают значения мусора в конце?
  3. Почему компилятор не сделал выдает любую ошибку или исключение?
  4. В примере 4 Почему нет ошибки, когда мы пытались скопировать значение в конце, но не были инициализированы
  5. Как правильно инициализировать умный указатель в этот случай? Изменится ли что-нибудь, если это массив BYTE вместо char;

Ответы [ 2 ]

2 голосов
/ 04 февраля 2020

Если Пример 1 верен, почему Пример 3 также дает правильный вывод?

make_unique<char[]>(size + 1); инициализирует все char с 0. Оба примера 1 и 3 don перезаписать это, потому что они копируют соответственно меньшие из size + 1 и size; и меньшее из size и size. Т.е. они оба копируют size char s

Что означают значения мусора в конце?

То, что ваша программа имеет неопределенное поведение. std::ostream::operator<<(char *) в этом случае читает байты, пока не увидит 0.

Почему компилятор не выдал ошибку или исключение?

Потому что C ++ не является безопасным. Вместо того, чтобы определять конкретное поведение (например, выбрасывать исключение) при доступе вне массива, целая программа не связана правилами C ++. Это называется «неопределенное поведение».

В примере 4 Почему нет ошибки, когда мы пытались скопировать значение в конце, но не были инициализированы

, потому что C ++ не является безопасным

Как правильно инициализировать умный указатель в этом случае? Изменится ли что-нибудь, если это массив BYTE вместо char;

Либо пример 1, либо пример 3 подойдут. Однако почему бы просто не использовать std::string?

2 голосов
/ 04 февраля 2020

Вам необходимо знать две вещи:

Во-первых, в C ++ memcpy_s это расширение Microsoft VC ++ CRT, специфицированное c. Он существует в C (добавлен в стандарт C11), но даже тогда реализации безопасных функций Microsoft часто не следуют стандарту C.

Второе, что является причиной Ваша проблема в том, что последний аргумент - это количество байтов для копирования. Поскольку вы указываете только size, ваш вызов не будет копировать строку с нулевым символом конца Вам необходимо скопировать size + 1 байт:

int r = memcpy_s(pstrText.get(), size + 1, strHello.c_str(), size + 1);
//                                                               ^^^^
//                    Copy plus one, to also copy the null-terminator
...