Перейти к содержимому

Gcnew в c что это

  • автор:

Что означают эти операторы в C++?

Здравствуйте! Например есть такой кусок кода на чистом C++:

void main()
WebClient^ client = gcnew WebClient;
>

Вопрос: что означает оператор «^»? И чем «gcnew» отличается от «new»?
И еще что означают вот эти операторы: «*» и «**»?

Лучший ответ

Операторы ^ и gcnew — это местные аналоги * и new из обычного C++, имеющие место в managed C++, он же C++ CLI. Последний представляет собой дикое сочетание вкуса и цвета нормального C++ и C#.

Остальные ответы

+^ обозначает вроде «ссылочный класс»..в общем там память выделяется не в нормальной куче а в куче под контролем сборщика мусора, оттого и GCnew.

Похожие вопросы
Ваш браузер устарел

Мы постоянно добавляем новый функционал в основной интерфейс проекта. К сожалению, старые браузеры не в состоянии качественно работать с современными программными продуктами. Для корректной работы используйте последние версии браузеров Chrome, Mozilla Firefox, Opera, Microsoft Edge или установите браузер Atom.

Gcnew в c что это

Совсем недавно я начал изучать С++, когда попытался создать Windows-приложение в Visual Studio, большая часть кода не вызвала у меня вопросов, но все же я так и не понял для чего используется оператор ^, и чем отличается gcnew от new. Подскажите пожалуйста, как можно подробнее, если есть возможность.

Регистрация: 21.03.2009
Сообщений: 2,193

Если вы хотите изучать нормальный C++ (или более политкорректно — «чистый C++»), то вам этого знать не обязательно. Операторы ^ и gcnew — это местные аналоги * и new из обычного C++, имеющие место в managed C++, он же C++ CLI. Последний представляет собой дикое сочетание вкуса и цвета нормального C++ и C#. Настоятельно не рекомендую копаться в этом довольно плохо сделанном гибриде, и заниматься либо C++, либо C#.
Подозреваю, что в Visual Studio вы при создании проекта выбираете тип проекта Visual C++ -> CLR. Консольное приложение на обычном C++ это Visual C++ -> Win32 -> Консольное приложение Win32.

Пользователь
Регистрация: 05.09.2009
Сообщений: 17

Да, вы правы, я именно так и делал. До этого я программировал на С# и только недавно начал изучать С++.

Регистрация: 12.11.2014
Сообщений: 4

Скорее всего ^ выполнена в виде макроса, в котором прописано инстанциирование объекта шаблонного класса-обертки над указателем на ресурс, принимающего тип в качестве параметра, тогда такая штука скажем
String^ ptr = gcnew String(«abc»);

template // в качестве T будет String
class GC
T* value; // суть в том что наш ресурс расположен по этому указателю
GC()
// хитрая реализация, вызовы методов GC
>
GC( const GC& other )
// хитрая реализация
>
GC& operator = ( const GC& other )
// хитрая реализация
>
~GC( )
// хитрая реализация
>
GC* operator -> ()
< return this; >
>;
то есть в обертку над указателем на ресурс того типа (в данном случае String) который создаем.

kovalexius
Посмотреть профиль
Найти ещё сообщения от kovalexius

Строка (C++/CLI и C++/CX)

Среда выполнения Windows и среда CLR представляют строки в виде объектов, управление выделяемой памятью которых осуществляется автоматически. Это значит, что в случае выхода строковой переменной за пределы области видимости или завершении работы приложения явно отменять память для строки не требуется. Чтобы указать, что управление временем существования строкового объекта должно осуществляться автоматически, следует объявить тип string с помощью модификатора дескриптор объекта (^).

Среда выполнения Windows

Архитектура среды выполнения Windows требует реализации типа данных String в пространстве имен Platform . Для удобства в Visual C++ также предусмотрен тип данных string , являющийся синонимом для Platform::String в пространстве имен default .

Синтаксис

// compile with /ZW using namespace Platform; using namespace default; Platform::String^ MyString1 = "The quick brown fox"; String^ MyString2 = "jumped over the lazy dog."; String^ MyString3 = "Hello, world!"; 

Требования

Параметр компилятора: /ZW

Среда CLR

При компиляции с параметром /clr компилятор преобразует строковые литералы в строки типа String. Для сохранения обратной совместимости с существующим кодом у этого правила есть два исключения:

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

В компиляторе также есть встроенная поддержка трех операторов, которые можно переопределять для настройки их поведения:

  • System::String^ operator +( System::String, System::String);
  • System::String^ operator +( System::Object, System::String);
  • System::String^ operator +( System::String, System::Object);

После передачи String компилятор при необходимости упаковывает, а затем объединяет объект (с помощью ToString) со строкой.

Курсор («^») означает, что объявленная переменная является дескриптором управляемого объекта C++/CLI.

Требования

Параметр компилятора: /clr

Примеры

В следующем примере кода демонстрируется объединение и сравнение строк.

// string_operators.cpp // compile with: /clr // In the following code, the caret ("^") indicates that the // declared variable is a handle to a C++/CLI managed object. using namespace System; int main() < String^ a = gcnew String("abc"); String^ b = "def"; // same as gcnew form Object^ c = gcnew String("ghi"); char d[100] = "abc"; // variables of System::String returning a System::String Console::WriteLine(a + b); Console::WriteLine(a + c); Console::WriteLine(c + a); // accessing a character in the string Console::WriteLine(a[2]); // concatenation of three System::Strings Console::WriteLine(a + b + c); // concatenation of a System::String and string literal Console::WriteLine(a + "zzz"); // you can append to a System::String^ Console::WriteLine(a + 1); Console::WriteLine(a + 'a'); Console::WriteLine(a + 3.1); // test System::String^ for equality a += b; Console::WriteLine(a); a = b; if (a == b) Console::WriteLine("a and b are equal"); a = "abc"; if (a != b) Console::WriteLine("a and b are not equal"); // System:String^ and tracking reference String^% rstr1 = a; Console::WriteLine(rstr1); // testing an empty System::String^ String^ n; if (n == nullptr) Console::WriteLine("n is empty"); >
abcdef abcghi ghiabc c abcdefghi abczzz abc1 abc97 abc3.1 abcdef a and b are equal a and b are not equal abc n is empty 

В следующем примере показано, что предоставляемые компилятором операторы можно перегружать, и что компилятор будет искать перегрузку функции на основе типа String.

// string_operators_2.cpp // compile with: /clr using namespace System; // a string^ overload will be favored when calling with a String void Test_Overload(const char * a) < Console::WriteLine("const char * a"); >void Test_Overload(String^ a) < Console::WriteLine("String^ a"); >// overload will be called instead of compiler defined operator String^ operator +(String^ a, String^ b) < return ("overloaded +(String^ a, String^ b)"); >// overload will be called instead of compiler defined operator String^ operator +(Object^ a, String^ b) < return ("overloaded +(Object^ a, String^ b)"); >// overload will be called instead of compiler defined operator String^ operator +(String^ a, Object^ b) < return ("overloaded +(String^ a, Object^ b)"); >int main() < String^ a = gcnew String("abc"); String^ b = "def"; // same as gcnew form Object^ c = gcnew String("ghi"); char d[100] = "abc"; Console::WriteLine(a + b); Console::WriteLine(a + c); Console::WriteLine(c + a); Test_Overload("hello"); Test_Overload(d); >
overloaded +(String^ a, String^ b) overloaded +(String^ a, Object^ b) overloaded +(Object^ a, String^ b) String^ a const char * a 

В следующем примере показано, что компилятор различает собственные строки и строки String.

// string_operators_3.cpp // compile with: /clr using namespace System; int func() < throw "simple string"; // const char * >; int func2() < throw "string" + "string"; // returns System::String >; template void func3(T t) < Console::WriteLine(T::typeid); >int main() < try < func(); >catch(char * e) < Console::WriteLine("char *"); >try < func2(); >catch(String^ str) < Console::WriteLine("String^ str"); >func3("string"); // const char * func3("string" + "string"); // returns System::String > 
char * String^ str System.SByte* System.String 

Кратко и быстро разбираемся с C++ CLI

Так сложилось, что по мере рабочей необходимости мне приходится интенсивно использовать C++/CLI и, соответственно, довольно часто объяснять новичкам, что это, как работает, как использовать и, зачем вообще надо. Так что со временем появилось желание написать статью с обзором языка, ответами на некоторые распространенные вопросы и показать места, где могут удачно лечь грабли.

Что это?

Когда Microsoft создавала платформу .Net, то она решила дать программистам писать под нее на нескольких уже существующих языках, в синтаксис которых были внесены некоторые изменения — VB, C++. Речь пойдет именно о последнем. Точнее, если мне не изменяет память, в первой редакции язык назывался C++ with managed extensions. Название как бы само намекает на сущность — вот мы вам дали плюсы с расширениями и теперь вы сможете разрабатывать под .Net на уже известных C++, при этом оставив всю мощь исходного языка. Собственно, первая версия расширения синтаксиса была ужасна чуть более чем полностью, и делала код похожим на попытку закодировать и отправить в космос диалог Жириновского и Черномырдина:

//объявляем управляемый класс
public __gc class Class1
public :
// метод, принимающий int по ссылке и управляемый массив
int Method1(__gc int &refValue, __gc int [] managedArr);
>;

* This source code was highlighted with Source Code Highlighter .

К тому же, в этом синтаксисе не было отличий между указателем на нативный тип и на управляемый (в обоих случаях использовалась «*»), не было ключевого слова для обозначения нулевого указателя и прочее. Это и толкнуло Microsoft на создание новой ревизии языка, о которой и пойдет речь в данной статье.
Замечание: эти две версии синтаксиса называются, как ни странно, «old syntax» и «new syntax», и какую именно использовать можно выбирать в настройках компиляции проекта. Впрочем, при создании новых сборок лучше использовать новый синтаксис, так как старый помечен как устаревший и просто плох.

Зачем нужно?

1) С помощью данного языка сферический программист в вакууме сможет разрабатывать полноценное .Net-приложение на любимых плюсах. Честно говоря, мне сложно представить этого извращенца, да и Microsoft такому подходу явно не способствует хотя бы тем, что не делает под C++ дизайнера визуальных компонент. Собственно, правильно делает, ибо для таких целей есть более выразительные языки, тот же C#. Так что это возможность скорее теоретическая.

2) Можно вызывать уже написанный на плюсах код. Действительно, поскольку у нас остались все возможности обычного C++, то можно создавать управляемые обертки для существующих классов на нативных плюсах. Это дает намного большие возможности по вызову неуправляемого кода, нежели PInvoke, который с классами работать не умеет.

3) Можно писать на C++ CLI модули, где производительность критична. Действительно, среди всего зоопарка языков под .Net С++ уникален тем, что на нем можно писать код, который напрямую использует выделение и освобождение памяти, работу с указателями. Например, так:

//управляемый класс, который может потом использоваться любой .Net–сборкой
public ref Class1
public :
//этот метод так же можно использовать во всех .Net-сборках
void Method1();
BYTE *buff = new BYTE[100];

* This source code was highlighted with Source Code Highlighter .

Как работает?

Все очень просто. При компиляции кода на С++/СLI получается сборка, содержащая как MSIL код, так и машинные команды, в которые превратились строки, написанные на «чистых» плюсах. «Но как же быть с кроссплатформеностью?» — спросите вы, и будете совершенно правы. Никак. В частности, это означает, что не получится собрать один и тот же бинарник для 32 и 64 битных версий (собрать все под «Any CPU»). Такова расплата за использование всех возможностей С++. Естественно, это относится к тому варианта, когда используется микс из управляемого и неуправляемого кода. Всего есть несколько вариантов компиляции:
• /clr — поддержка управляемого и нативного кода с использованием нового синтаксиса.
• /сlr:pure — нативный код не поддерживается. Однако при этом можно использовать небезопасный ) код, в той мере, как это можно делать, к примеру, в С#-сборках при использовании директивы unsafe.
• /clr:safe — Только управляемый безопасный код. Аналог — компиляция C#-сборки без использования unsafe.
• /clr:oldSyntax — аналог /clr, только используется старый синтаксис.

Как выглядит?

Вот примеры сравнения основных конструкций для С# и C++/CLI.

Объявление класса

public sealed class Class1 : Class2

* This source code was highlighted with Source Code Highlighter .

public ref class Class1 sealed : Class2

* This source code was highlighted with Source Code Highlighter .

Объявление структуры

public struct Class1 : IEquatable

* This source code was highlighted with Source Code Highlighter .

public value class Class1 : IEquatable

* This source code was highlighted with Source Code Highlighter .

Объявление интерфейса

public interface ISomeInterface

* This source code was highlighted with Source Code Highlighter .

public interface class ISomeInterface

* This source code was highlighted with Source Code Highlighter .

Объявление перечисления

public enum Enum1
Val1,
Val2
>

* This source code was highlighted with Source Code Highlighter .

public enum class Enum1
Val1,
Val2
>

* This source code was highlighted with Source Code Highlighter .

Создание управляемого объекта

object obj = new object ();

* This source code was highlighted with Source Code Highlighter .

* This source code was highlighted with Source Code Highlighter .

В C++/CLI для обозначения ссылок на управляемые объекты используется «^» вместо «*». Это очень удобно чтобы различать объекты, которые потом надо удалить и те, которые не надо. Также при создании локального ссылочного объекта можно использовать семантику стека:
Object obj();
Это имеет смысл либо при использовании объектов, реализующих IDisposable (речь об этом пойдет позже) либо для value-типов. Заметим, что в плане хранения и использования value-типов С++/CLI дает большую свободу, чем C#, поскольку программист может сам выбирать — использовать ссылку или значение. Таким образом вполне можно в некоторых ситуация сэкономить на количестве boxing/unboxing операций.

Создание управляемого массива

* This source code was highlighted with Source Code Highlighter .

* This source code was highlighted with Source Code Highlighter .

Неуправляемые массивы при этом создаются как обычно.

Передача параметров в метод

void Method( int byValue, ref int byRef, out int outValue);

* This source code was highlighted with Source Code Highlighter .

void Method( int byValue, int %byRef, [ out ] int %outValue);

* This source code was highlighted with Source Code Highlighter .

Как видно из этого примера, если «^» — это аналог «*» из обычного C++, то «%» — это аналог «&». Причем аналогия весьма точная и прослеживается не только при передаче параметров, но и при получении ссылки например:

* This source code was highlighted with Source Code Highlighter .

Переопределение метода

override void Method();
* This source code was highlighted with Source Code Highlighter .

* This source code was highlighted with Source Code Highlighter .

Реализация шаблона IDisposable

class Class1 : Disposable
public void Dispose()
this .Dispose( true );

protected virtual void Dispose( bool disposing)
if (disposing)
//release managed resources
>

//release unmanaged resources
>

~Class1()
this .Dispose( false );
>
>

* This source code was highlighted with Source Code Highlighter .

ref class Class1
public :
//Эквивалент Dispose
~Class1()
//release managed resources

//call finalizer
this ->!Class1();
>

//Аналог финализатора
!Class1()
//release unmanaged resources
>
>

* This source code was highlighted with Source Code Highlighter .

В C++/CLI часть шаблона Disposable за нас реализует компилятор, и это с виду отличается от типичной реализация интерфейса. Более того, все тот же компилятор не позволит реализовать IDisposable напрямую. Впрочем, когда к этому привыкаешь, то понимаешь, что такое поведение довольно логично — избавляет от необходимости писать кучу повторяющегося кода. Так же в своем стремлении сделать освобождение ресурсов похожим на обычный С++ создатели языка пошли еще дальше и явный вызов Dispose можно сделать двумя способами:

* This source code was highlighted with Source Code Highlighter .

delete obj;
* This source code was highlighted with Source Code Highlighter .

Так же можно использовать семантику стека для гарантированной очистки ресурсов:
C++/CLI:

B();
>

* This source code was highlighted with Source Code Highlighter .

соответствует
C#:

using (Class1 obj = new Class1())
B();
>
>

* This source code was highlighted with Source Code Highlighter .

Что осталось за кадром?

Понятно, что в одну статью все поместить не удалось. Не рассмотренными остались такие вопросы как:
• Синтаксис делегатов, свойств, методов расширения, foreach и прочее
• Жонглирование из управляемого в неуправляемый и обратно объектами, массивами и прочим
• Что поддерживается и нет из того, что есть в С# и в обычном C++
• Особености компиляции приложений со сборками С++/CLI
• Вопросы производительности. Когда и в чем можно получить выигрыш? Где можно внезапно потерять?

Что почитать?
Заключение

Среди всех остальных языков под .Net C++/CLI является довольно специфичным. Вряд ли на нем имеет смысл разрабатывать стандартное .Net приложение, зато в качестве коммуникации с существующим C++ кодом или для задач оптимизации – самое оно.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *