Выделение массива структур из .NET в C ++: когда он выполняет копирование? - PullRequest
9 голосов
/ 16 декабря 2011

Рассмотрим структуру, подобную System.Drawing.Point - структура с LayoutKind.Sequential и содержащая только примитивные члены. У меня есть массив C # таких структур.

Я передаю его (неуправляемой) функции C ++ через P / Invoke. На стороне C ++ есть соответствующее определение структуры (например, struct Point { int x, y; };). Функция принимает Point* аргумент.

Мой вопрос: в каких случаях CLR копирует данные и в каких случаях он просто прикрепляет их? Переменные включают в себя:

  • Тип массива: одномерный или прямоугольный
  • C # определение функции - с использованием Point* или Point[] / Point[,]
  • с использованием fixed(Point* pointer = array) или без

Я хочу избежать копирования, потому что это медленно.

Ответы [ 2 ]

2 голосов
/ 20 декабря 2011

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

  1. Распределение данных с помощью PInvoke
  2. Копирование и закрепление
  3. Типы Blittable и Non-Blittable
  4. Маршаллинг по умолчанию для типов значений

От # 2:

Форматированные классы blittable имеют фиксированное расположение (форматированное) и общее представление данных как в управляемой, так и в неуправляемой памяти. Когда эти типы требуют маршалинга, указатель на объект в куче передается вызываемому напрямую.

И ваша структура Point приведена в качестве примера в # 3, поэтому она квалифицируется как blittable тип.

Я заметил некоторые накладные расходы на закрепление объектов здесь , но это было для fixed byte[], которое может отличаться от вашего Point[].

0 голосов
/ 20 декабря 2011

Структуры ссылаются по значению, а классы - по ссылке.

Это означает, что у вас всегда есть структура, и вы делаете присваивание, ее значения копируются, например, когда вы используете int a = b; a имеет значение b, а не точку, поэтому b, так что если вы измените значение a, b не будет обновлено.

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

Предположим, у вас есть

Point p = new Point(0, 1);
Point[] pa = new Point[10];
pa[0] = p;
++p.X;

Поскольку Point - это структура (тип значения) при печати значений

p: {1, 1}
pa[0]: {0, 1}
pa[1-9]: {0, 0}

Для C ++ вы можете использовать foo (Point * pa) или foo (Point [] pa) для тех же результатов; в C # используйте foo (Point [] pa) в одномерном массиве. Для прямоугольного foo (Point ** pa) в C ++ и foo (Point [] []) в C #

...