Для «копирования и вставки» мы используем memcpy и memmove в зависимости от того, перекрываются ли src и dest, верно? Есть ли инкапсулированная функция «вырезать и вставить»? Если нет, существует ли относительно четко определенный способ добиться этого? Единственный способ, который я могу придумать, - это установить избыточную часть в 0 после memmove.
Чтобы уточнить код, с помощью mem_xxx, я хочу, чтобы массив с именем arr был «2345\0\0\0\0» вместо «234545\0\0», если использовать memmove.
char *arr = new char[8];
for ( int i = 2; i <= 5; i++ ) {
arr[i] = char( i );
}
mem_xxx( arr, arr + 2, 5 - 2 + 1 );
Операции «вырезать» и «вставить» не имеют смысла на уровне абстракции необработанной памяти. При вырезании и вставке текста весь текст после этой точки сдвигается влево или вправо, чтобы освободить место для вставленного текста или не оставить пробелов при вырезании текста. Вы не можете вот так сдвинуть всю память «вправо» от какой-то точки влево или вправо.
Ближе всего в C++ к эффекту «комбинированного вырезания и вставки» может быть std::rotate.
Если вы хотите, вы можете написать memmovezap(), который заменяет исходный байт нулем после его копирования. Совершенно непонятно, зачем вам это нужно, но это несложно сделать.
Индексы массива 6 и 7 будут неинициализированы после вашего кода.
@Atmo - это не код C!! Тег C недействителен.
У меня возник этот вопрос, когда я пытался поцарапать реализацию стека, имитирующую std::deque, где код stl src выполнял перемещение памяти, когда правый или левый конец «карты» все еще имеет большую неиспользованную часть. Обратите внимание, что «map» — это не std::map, а массив указателей на Tp, подробности см. в gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/….
Я бы просто скопировал содержимое в память, а затем использовал memset, чтобы обнулить регион. Реализация этих функций быстрая, копирование слов вместо байтов и т. д. Я до сих пор не думаю, что это то, что вы действительно хотите сделать, поскольку нет никакого реального смысла устанавливать память в 0.
Вы не инициализируете все элементы массива, а это значит, что некоторые значения будут неопределенными. А в C++ использование неопределенных значений каким-либо образом приводит к неопределенному поведению. Даже копирование этих значений в другое место будет использовать эти значения (иначе их невозможно скопировать).
@PkDrew: Похоже, вы пытаетесь создать универсальный контейнер C++, когда говорите «имитировать std::deque». В этом случае о таких вещах, как memmove
, совершенно не может быть и речи. Например, вы не можете запомнить std::string
. Вы должны знать о std::move
при написании такого контейнера. Это включает в себя понимание std::move
, которое на самом деле не уничтожает перенесенный объект.
@MSalters, большое спасибо за ваш ответ, позвольте мне воспользоваться этой возможностью, чтобы подробнее рассказать об этом здесь. Игрушка представляет собой заранее выделенный массив указателей на элементы, обозначенные как Tp, т. е. Tp **arr = new Tp*[num_nodes]; Хитрость здесь в том, что вместо использования массива из головы мы используем его из середины, таким образом, для push_front() вы помещаете его влево, а для push_back() — вправо. Теперь, если какой-либо конец достигнут, но большая часть другого конца все еще свободна, в этом случае текущий действительный диапазон перемещается в сторону запасного конца, отсюда и этот вопрос.
@PkDrew: Обратите внимание, что ни один из стандартных контейнеров не управляет содержащимися объектами с помощью указателей. Это довольно плохо для местности отсчета. А для контейнера типа двухуровневой очереди это важно. Когда это менее важно, std::list
имеет гораздо более дешевый push_front
/push_back
.
В библиотеке STL для C++ для этого есть функция rotate
. Обратите внимание: вы спрашиваете просто о вращении элементов в заданном диапазоне.
#include <algorithm>
int main() {
char arr[8]{};//char* arr = new char[8];
for (int i = 2; i <= 5; i++) {
arr[i] = char(i);
}
// first middle last
// | | |
// [0 0 2 3 4 5] 0 0
// [2 3 4 5 0 0] 0 0
std::rotate(arr, arr + 2, arr + 6);
}
Если вас все еще интересует C, вы можете реализовать аналогичную функцию.
Иллюстрация работы алгоритма:
0 0 2 3 4 5 0 0
2 0 0 3 4 5 0 0
2 3 0 0 4 5 0 0
2 3 4 0 0 5 0 0
2 3 4 5 0 0 0 0
Спасибо за ваш ответ, приятель, да, это было бы то, что я ищу, а именно реализация, которая, надеюсь, будет введена в стандарт. Правда, для моей цели необходимо вращение влево или вправо, а массив, которым манипулируют, поддерживается внутри класса с помощью итераторов, поэтому я могу отметить допустимый диапазон.
Да, выглядит необычно. Например, команда std::rotate(arr, arr + 4, arr + 6);
вернет arr
в предыдущее состояние, т.е. переместит элементы вправо на 2 позиции.
Обратите внимание, что показанный вами код — это не C, а C++.