Конверсия управляемых языков в неуправляемые
TRANSCRIPT
Dmitri NesterukJetBrains
Managed language = C#, Java, D etc.GC (garbage collector), Unicode, …
Unmanaged languageSomething that compiles to native codeMore control, less safetyC/C++, VHDL, etc.
PerformanceStop-the-world GCLow-level control (e.g., SIMD)Collections (containers), multithreading
Defense against reverse-engineeringC#, Java are easy to decompile
Hardware supportCUDA, Xeon Phi
Portability (surprise!)Sudden desire to write everything in С++
Lex the source codeBuild ASTResolve symbolsTraverse the tree, translating it to a different languagePerfect translation is (of course) impossible
Translate syntax with fidelityFill the gaps in what’s missing
Replace equivalent constructsList<> vector<>
Handle cases where 1-to-1 mapping is impossible
Integral typesUse types from <cstdint>int int32_t, byte uint8_t, etc.
float/double as-isExtended precision types (System.Decimal)
Need external libs
Slightly different init rules
Unicode Most LoB apps do not absolutely require Unicode (nice to have)
Relatively safe option: string std::wstringchar wchar_tSlightly more careless option: string/char
A completely safe solution has to allow strings to be nullptrI.e., you either use char* or option<string>Expensive, tedious, just use myString.empty()
Unicode in source (identifiers, literals, …) won’t work
class Person{string name;int age;
}
class Person { std::string name;int32_t age;
public:Person();
};
Managed languagesGive types default valuesAllow initialization right in the declaration
In both cases, initialization happens in the (generated) ctorIn C++, types don’t have default values. So we are forced to make a constructor ourselves
Property = field+getter+setterCan be read or write-onlyCan be automatic
Name of field not specified explicitlyOffers no benefit over a field in C++
Can have an inline initializerMore ctor abuse
Two options hereGetXxx/SetXxx (safe, tedious)__declspec(property)(not C++ standard, but nicer)
int age;public int Age{get { return age; }set { age = value; }
}
// automaticpublic int Age{ get; set; }
__declspec(property(get = GetAge, put = PutAge)) int Age;
int GetAge() const { return age; }
void PutAge(int value) { … }
// laterPerson p;p.Age = 123; // calls PutAge()
Used in many places, e.g.:Handling UI interactionsProperty change notifications
C++ doesn’t have themBoost.SignalsTricky since event subscription is done with +=
And unsubscription with −=
template <typename T> class INotifyPropertyChanged{public:
signal<void(const T*, string)> PropertyChanged;
};
class Player : public INotifyPropertyChanged<Player>{int age;
public:__declspec(property(get = GetAge, put = PutAge)) int Age;int GetAge() const { return age; }void PutAge(int value){if (value == age) return;PropertyChanged(this, "Age"); // oops, a string! (macro?)age = value;
}
“The big problem”GC non-GC translationStore everything as shared_ptr
Replace every `new` with make_shared
Detecting use-cases for make_unique very difficultCircular references (weak_ptr<>?)
References require #includesNeed a list of typeheader for STL etc.
Circular references may need forward declarationsHeader groupings (at namespace or folder level)
Very tricky internal consistency (topological sort)Also a good idea for IDEs
Type translation is (relatively) easyint int32_tList<T> vector<T>
Function call translation is harderList.Add() vector.emplace_back(), but…Value vs ref. stuff
We need two convertersOne for .H filesAnother for .CPP files (implementation)
The option of doing everything inline isn’t considered
There are situations where 100% inlining doesn’t work
Naming conventionClean Unicode handlingAutomated API mapping
[email protected]@dnesterukCome to the JB booth! (R#C++, CLion)