C# к C++ 'глюки'

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

Есть ли что-нибудь, что собирается сбить меня с моих ног, которые предотвратили бы меня от просто взятия C++ и движения для него?

25
задан George Johnston 27 January 2010 в 14:27
поделиться

14 ответов

C ++ имеет так много готов, которые я не могу перечислять их все. Сделайте поиск «C # VS C ++». Несколько основных вещей, которые нужно знать: В C ++:

  • struct и класс в основном то же самое (видимость по умолчанию для структуры - публичная, она частная для класса).
  • Оба структуры, так и класса могут быть созданы либо на куче, либо в стеке.
  • Вы должны управлять кучей самостоятельно. Если вы создадите что-то с «новым», вы должны удалить его вручную в какой-то момент.
  • Если производительность не является проблемой, и у вас есть очень мало данных для перемещения, вы можете избежать проблемы управления памятью, имея все на стеке и используя ссылки (и оператор).
  • Научитесь иметь дело с .h и .cpp. Неразрешенные внешние могут быть у вас хуже кошмара.
  • Вы не должны вызывать виртуальный метод от конструктора. Компилятор никогда не скажет вам, так что я делаю.
  • Чехол коммутатора не принудительный «разрыв» и по умолчанию проходит через.
  • Там не такая вещь, как интерфейс. Вместо этого у вас есть класс с чистыми виртуальными методами.
  • C ++ Aficionados - опасные люди, живущие в пещере и выжившие на свежей крови программистов C # / Java. Поговорите с ними о своем любимом языке тщательно.
28
ответ дан 28 November 2019 в 17:48
поделиться
2
ответ дан 28 November 2019 в 17:48
поделиться

Файлы заголовка! Вы просим, ​​- так почему мне нужно написать метод объявлений дважды каждый раз? »

2
ответ дан 28 November 2019 в 17:48
поделиться
  <label ... style = "width: auto; color: inherit" />
-121--2669365-

Связывание

Связывание с внешними библиотеками не так прощения, как он находится в .NET, $ Божество Помогите вам, если вы смешиваете что-то скомпилированное с разными ароматами того же MSVCRT (DEBUG, MultiThread, Unicode ...)

Строки

, и вам придется иметь дело с Unicode VS Strings ANSI, это не совсем одинаково.

повеселиться :)

0
ответ дан 28 November 2019 в 17:48
поделиться

Следующее не предназначено для отговаривания каким-либо образом: D

C ++ - это минное поле Gotcha, это относительно ручное, если вы не используете шаблоны и STL - и просто Используйте объектную ориентацию, но даже тогда это монстр. В этом случае на основе объекта на основе программирования (вместо объектно-ориентированного программирования) делает его даже тамер - часто эта форма C ++ применяется в определенных проектах (то есть, не используйте никаких функций, которые имеют даже шанс на наивно используемые).

Однако вы должны узнать все эти вещи, так как его очень мощный язык, если вам удается пройти через MINEFIELD. Если вы хотите узнать о Gotcha, вам лучше получить книги из трав Sutter, Скотт Майерса, а также Bjarne Strustrup. Также систематически проходит через C ++ FAQ Lite , поможет вам понять, что это действительно требует 10 или около того книг, чтобы превратиться в хороший программист C ++.

-4
ответ дан 28 November 2019 в 17:48
поделиться

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

... ричи

-121--2948927-

Указатели и выделение памяти

... Я тоже парень C #, и я все еще пытаюсь обернуть голову о надлежащих практиках памяти в C/C + +.

-121--1469293-

Вот краткий обзор управляемого C++ здесь . Статья о написании неуправляемой оболочки с помощью управляемого C++ здесь . Здесь есть еще одна статья о смешивании неуправляемого кода с управляемым кодом C++ здесь .

Использование управляемого C++ упростит использование IMHO в качестве моста к миру C # и наоборот.

Надеюсь, что это поможет, С уважением, Том.

1
ответ дан 28 November 2019 в 17:48
поделиться

Коллекция мусора!

Помните, что каждый раз, когда вы Новый Объект, вы должны быть ответственным для вызова Удалить .

26
ответ дан 28 November 2019 в 17:48
поделиться

Нет проверки времени выполнения

Один C ++ подвалы - это поведение, когда вы пытаетесь сделать что-то, что может быть недействительным, но что можно проверить только во время выполнения - например, разыграть только указатель Это может быть нулевым или доступ к массиву с индексом, который может быть вне диапазона.

Философия C # подчеркивает правильность; Все поведение должно быть четко определено и, в таких случаях, он выполняет проверку выполнения предварительных условий и бросает четко определенные исключения, если они не удаются.

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

6
ответ дан 28 November 2019 в 17:48
поделиться

Сырая память Twiddling. Профсоюзы, Memsets и другая прямая память пишет. В любое время кто-то пишет на память как последовательность байтов (в отличие от как объектов), вы теряете большую часть способности рассуждать по поводу кода.

0
ответ дан 28 November 2019 в 17:48
поделиться

Традиционные камнические блоки для людей, приходящих к C ++ из C # или Java, являются управление памятью и полиморфное поведение:

  • , в то время как объекты всегда живут на куче и являются мусором, собираемым в C # / Java, вы Может иметь объекты в статическом хранилище, стеке или куче («бесплатный магазин» в стандартной погоре) в C ++. Вы должны очистить вещи, которые вы выделяете из кучи (New / Delete). Бесценная техника для борьбы с этим - Raii .
  • Наследование / полиморфизм работают только через указатель или ссылку в C ++.

Есть много других, но это, вероятно, сначала получит вас.

2
ответ дан 28 November 2019 в 17:48
поделиться

Указатели и распределение памяти

... Я тоже C # парень, и я все еще пытаюсь обернуть голову вокруг правильной практики памяти в C / C ++.

1
ответ дан 28 November 2019 в 17:48
поделиться

Просто добавить некоторые другие, которые еще не были упомянуты в других ответах:

const: C# имеет ограниченное представление о const. В C++ 'const-корректность' важна. Методы, которые не изменяют свои параметры ссылки, должны брать const-ссылки, например,

void func(const MyClass& x)
{
    // x cannot be modified, and you can't call non-const methods on x
}

функции-члены, которые не изменяют объект, должны быть помечены const, т.е.

int MyClass::GetSomething() const // <-- here
{
    // Doesn't modify the instance of the class
    return some_member;
}

Это может показаться ненужным, но на самом деле очень полезно (см. следующий пункт о временных параметрах), а иногда и необходимо, так как такие библиотеки, как STL, являются полностью const-корректными, и вы не можете приводить const вещи к неконстантным вещам (не используют const_cast!Ever!). Также полезно, чтобы звонящий знал, что что-то не будет изменено. Лучше подумайте об этом так: если вы пропустите const, вы говорите, что объект будет изменен.

Temporary objects: Как уже упоминалось в другом ответе, С++ гораздо больше относится к стоимостно-семантике. Временные объекты можно создавать и уничтожать в выражениях, например:

std::string str = std::string("hello") + " world" + "!";

Здесь первый + создает временную строку с "hello world". Второй + соединяет временный с "!", давая временный содержащий "hello world!", который затем копируется в str. После того, как высказывание будет завершено, временный мир немедленно уничтожается. Чтобы еще больше усложнить ситуацию, C++0x добавляет ссылки на значение, чтобы решить эту проблему, но это выходит за рамки данного ответа!

Можно также привязать временные объекты к const ссылкам (еще одна полезная часть const). Рассмотрим еще раз предыдущую функцию:

void func(const MyClass& x)

Она может быть вызвана явно с временным MyClass:

func(MyClass()); // create temporary MyClass - NOT the same as 'new MyClass()'!

Создан экземпляр MyClass, на стеке, функционал получает к нему доступ, а затем временный MyClass уничтожается автоматически после возврата функционала. Это удобно и обычно очень быстро, т.к. куча не задействована. Замечание 'new' возвращает указатель, а не ссылку и требует соответствующего 'delete'. Также можно напрямую присваивать временные значения const ссылкам:

const int& blah = 5;   // 5 is a temporary
const MyClass& myClass = MyClass(); // creating temporary MyClass instance
// The temporary MyClass is destroyed when the const reference goes out of scope

Const ссылки и временные значения часто встречаются в хорошем стиле C++, и эта работа сильно отличается от C#.

RAII, безопасность исключений и детерминистические деструкторы. На самом деле это полезная особенность C++, возможно даже преимущество перед C#, и это стоит прочитать, так как это также хороший стиль C++. Я не буду рассказывать об этом здесь.

Наконец, я просто брошу в этот указатель, а не ссылку :)

.
4
ответ дан 28 November 2019 в 17:48
поделиться

Есть много различий, но самое большое, что я могу вспомнить, программисты, пришедшие с Java / C #, всегда ошибаются, а чего никогда осознать , что они ошибаются, - это семантика значений C ++.

В C # вы привыкли использовать new каждый раз, когда хотите создать объект. И всякий раз, когда мы говорим об экземпляре класса, мы действительно имеем в виду «ссылку на экземпляр класса». Foo x = y не копирует объект y , а просто создает другую ссылку на любой объект y , на который ссылается.

В C ++ существует четкое различие между локальными объектами, размещенными без new ( Foo f или Foo f (x, y) , и динамически выделяемыми one ( Foo * f = new Foo () или Foo * f = new Foo (x, y) ). А в терминах C # все является типом значения. Foo x = y фактически создает копию самого объекта Foo .

Если вам нужна эталонная семантика, вы можете использовать указатели или ссылки: Foo & x = y создает ссылку на объект y . Foo * x = & y создает указатель на адрес, по которому находится y . И копирование указатель делает именно это: он создает другой указатель, который указывает на то, на что указывал исходный указатель. Таким образом, это похоже на семантику ссылок C #.

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

Динамически размещенные объекты не уничтожаются, пока вы не вызовете delete .

Пока что, наверное, ты со мной. Новичков в C ++ учат этому довольно скоро. Сложность заключается в том, что это означает , как это влияет на ваш стиль программирования:

В C ++ по умолчанию надо создавать локальные объекты. Не выделяйте с помощью new , если в этом нет крайней необходимости.

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

class IntArrayWrapper {
  explicit IntArrayWrapper(int size) : arr(new int[size]) {} // allocate memory in the constructor, and set arr to point to it
  ~IntArrayWrapper() {delete[] arr; } // deallocate memory in the destructor

  int* arr; // hold the pointer to the dynamically allocated array
};

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

Допустим, нам нужен массив из x целых чисел, вместо того, чтобы делать это:

void foo(int x){
  int* arr = new int[x];
  ... use the array ...
  delete[] arr; // if the middle of the function throws an exception, delete will never be called, so technically, we should add a try/catch as well, and also call delete there. Messy and error-prone.
}

вы можете сделать это:

void foo(int x){
  IntArrayWrapper arr(x);
  ... use the array ...
  // no delete necessary
}

Конечно, такое использование локальных переменных вместо указателей или ссылок означает, что объекты копируются довольно много bit:

Bar Foo(){
  Bar bar;
  ... do something with bar ...
  return bar;
}

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

Вместо этогокласс Bar нужно просто спроектировать так, чтобы его копирование делало то, что нам нужно. Возможно, ему следует внутренне вызвать new , чтобы выделить объект, который может жить столько, сколько нам нужно. Затем мы могли бы сделать копирование или присваивание «украдкой» этого указателя. Или мы могли бы реализовать какую-то схему подсчета ссылок, при которой копирование объекта просто увеличивает счетчик ссылок и копирует указатель, который затем следует удалять не при уничтожении отдельного объекта, а когда объект last уничтожается, и счетчик ссылок достигает 0.

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

Если вы хотите избежать еще большего копирования и готовы мириться с более громоздким использованием, вы можете включить «семантику перемещения» в своих классах, а также (или вместо) «семантику копирования». Стоит приобрести эту привычку, потому что (а) некоторые объекты нелегко скопировать, но их можно переместить (например, класс Socket ), (б) это шаблон, установленный в стандартной библиотеке и ( в) он получит языковую поддержку в следующей версии.

С семантикой перемещения вы можете использовать объекты как своего рода «переносимый» контейнер. Это содержимое движется.В текущем подходе это делается путем вызова swap , который меняет местами содержимое двух объектов одного типа. Когда объект выходит за пределы области видимости, он разрушается, но если вы сначала замените его содержимое ссылочным параметром, содержимое не будет уничтожено, когда область действия закончится. Следовательно, вам не обязательно идти до конца и использовать интеллектуальные указатели с подсчетом ссылок только для того, чтобы позволить функциям возвращать сложные объекты. Неуклюжесть проистекает из того факта, что вы не можете вернуть их - вы должны заменить их на параметр ссылки (что-то вроде параметра ref в C #). Но языковая поддержка в следующей версии C ++ решит эту проблему.

Итак, самый большой подводный камень C # в C ++, который я могу придумать: не делать указатели по умолчанию. Используйте семантику значений и вместо этого настройте свои классы так, чтобы они вели себя так, как вы хотите, когда они копируются, создаются и уничтожаются.

Несколько месяцев назад я попытался написать серию сообщений в блоге для людей в вашей ситуации:
Часть 1
Часть 2
Часть 3

Я не на 100% доволен тем, как они оказались, но вы все равно можете найти их полезными.

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

18
ответ дан 28 November 2019 в 17:48
поделиться

Самая большая разница - это эталонная семантика C # (для большинства типов) и семантика значений C ++. Это означает, что объекты копируются гораздо чаще, чем в C #, поэтому важно обеспечить правильное копирование объектов. Это означает реализацию конструктора копирования и operator = для любого класса, имеющего деструктор.

1
ответ дан 28 November 2019 в 17:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: