Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
-
Upload
microsoft -
Category
Technology
-
view
971 -
download
2
description
Transcript of Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
Développement C++
Bonnes pratiques C++11
avec Visual C++Loïc Joly - CAST
Christophe Pichaud - Sogeti
www.castsoftware.com
www.fr.sogeti.com
Développement C++#mstechdays
Depuis votre smartphone sur :
http://notes.mstechdays.fr
De nombreux lots à gagner toute les heures !!!
Claviers, souris et jeux Microsoft…
Merci de nous aider à améliorer les Techdays !
Donnez votre avis !
Développement C++#mstechdays
PLANVisual C++ 2013
November 2013 CTP
Guide de survie en C++11
Interop WinRT
Développement C++#mstechdays
• C++11 : – Le contenu du November 2012 CTP (voir Développer
en natif avec C++11 http://microsoft.com/showcase/fr/fr/details/b67dd5c8-9a6e-4bb9-a1d2-
90f3f9ef3a09)
– =default, =delete, NSDI, greater<>, make_unique…
• C11 : Meilleur support– _Bool, déclaration au milieu de bloc, designated
initializer…
• Des retouches d’IHM (formatage du
code…)
Visual C++ 2013
Développement C++#mstechdays
• CTP = version beta. Installable sans danger.
• C++ 11– Génération des fonctions spéciales de déplacement, & and && for *this
– Initialisation thread safe des variables statiques
– Inheriting constructors
– alignof/alignas, __func__, Extended sizeof
– constexpr (partiel : Pas les fonctions membre)
– noexcept (partiel : Pas la version conditionelle)
• C++14– decltype(auto), auto function return type deduction
– generic lambdas (partiel : Liste de capture explicite uniquement)
• Autre– Resumable functions and await
November 2013 CTP
Développement C++#mstechdays
GUIDE DE SURVIE EN C++11
Autour de la sémantique de déplacement
Développement C++#mstechdays
Copie
• La destination vaut la valeur
qu’avait la source initialement
• La source est inchangée
• On peut continuer à utiliser la
source
• Fournit la strong exception
guarantee
• Plus lent
Déplacement
• La destination vaut la valeur qu’avait la source initialement
• On se moque de l’état de la source, tant qu’il est viable
• On va éviter d’utiliser la source par la suite
• Ne fournit que la basic exception guarantee
• …mais peut souvent être noexcept
• Plus rapide
Intérêt de déplacer
Développement C++#mstechdays
• Lvalue (ça possède un nom, on peut en prendre
l’adresse) et Rvalue (le reste)
• On peut surcharger une fonction là-dessus– int f(maClasses const &c); // Version pour les Lvalues
– int f(maClasses &&c); // Version pour les Rvalues
• Dans la seconde version, comme on sait qu’on est les
seuls à accéder à l’objet, on a le droit d’être destructif
Comment ça marche ?
Développement C++#mstechdays
• Constructeur et affectation par déplacement
– MaClasse(MaClasse &&c);
– MaClasse &operator=(MaClasse &&c);
• Pas générés automatiquement si un destructeur ou constructeur de
copie est défini
• Empêche la génération automatique d’un constructeur de copie
• Règle des 5 (ou règle des 0 !)
Comment rendre nos classes déplaçables
Développement C++#mstechdays
• Si possible, rendre les opérations de déplacement noexcept, et le
déclarer
– Utiliser une macro en attendant un meilleur support de VC++
• Réfléchir à l’état d’un objet depuis lequel il y a eu déplacement
• Préférez la règle des 0 à la règle des 5
– Utiliser des classes RAII pour gérer vos données, comme
[shared/unique]_ptr
– Éviter new et delete !
Quelques conseils sur les classes
déplaçables
Développement C++#mstechdays
1. Un type à sémantique de valeur (string, vector, map,
optional…)
2. Des pointeurs à propriété unique (unique_ptr / T*
observant (observer_ptr ?)
3. Des pointeurs à propriété partagée
(shared_ptr/weak_ptr)
Utiliser dans l’ordre de préférence
Développement C++#mstechdays
• Notion pédagogique inventée pas Scott Meyers
• T&& dans un contexte où T est déduit Universal reference
• Selon la manière dont on instanciera, une universal reference
deviendra :
– Une Lvalue reference si T est une Lvalue
– Une Rvalue reference si T est une Rvalue
• Idéal pour transmettre des arguments à l’aide de std::forward
• On n’a pas forcément le droit de toucher à la source !
• Fonctionne souvent assez mal avec la surcharge (car peut déjà tout
prendre en charge)
Universal references
Développement C++#mstechdays
La fonction va : On utilise : Et pour transmettre:
Utiliser la donnée
Ex: ofstream::open
void f(T const &t);ouvoid f(T &t);
g(t)
Dupliquer la donnée
Ex: vector::push_back
void f(T t); g(std::move(t))
void f(T const &t); void f(T&& t);
g(t)g(std::move(t))
Transmettre une donnée
dont on ne sait rien
Ex: make_shared
template <class T>void f(T &&t);
g(std::forward<T>(t))
Transmettre des arguments
Développement C++#mstechdays
Et avec des pointeurs intelligents ?Pour Utiliser
Une fonction manipulant uniquement
l’objet pointé
void f(T& t);
void f(T *t); // Si l’objet peut ne pas
exister
void f(observer_ptr<T> t); // au lieu de
T* ?
Une fonction prenant propriété d’un
objet géré par shared_ptr
void f(shared_ptr<T> t);
Une fonction prenant la propriété
unique d’un objet géré par pointeur
void f(unique_ptr<T> t);
Le reste Plus rare…
Développement C++#mstechdays
INTEROP WINRT
Développement C++#mstechdays
Conception de composants WinRT
C# / VB C++/CXC++ avec
WRL
Développement C++#mstechdays
Pourquoi faire des composants WinRT en C++
PerformanceGestionbatterie
Protection contre la
décompilation
Accès à Win32
Code existant
Développement C++#mstechdays
Scénarios d’applications C++ hybrides
Interface HTML/JS
Composants
WinRT C++
Interface C#/VB
ComposantsWinRT C++
InterfaceC++
ComposantsWinRT C#/VB
Développement C++#mstechdays
• Windows 8 utilise des composants COM– il existe l’interface IUnknown
– mais aussi IInspectable
• Ces composants COM sont nommés WinRT
• Il existe deux manières de coder– C++/CX qui sont des extensions du compilateur
– C++ Standard avec WRL : Windows Runtime Library
• WRL est inspirée de la librairie ATL
Le nouveau modèle de composants WinRT
Développement C++#mstechdays
• C’est un composant COM
• Il expose des metadata (.winmd)
• Il utilise les types Windows spécifiques
• Link avec RuntimeObject.lib
• Ne tourne que sous Windows 8.x– *En mode Desktop
– En mode Store App
Un composant WinRT
Développement C++#mstechdays
• Les entêtes sont définies dans– C:\Program Files (x86)\Windows Kits\8.1\Include\winrt\wrl
• async.h
• client.h
• def.h
• event.h
• ftm.h
• implements.h
• internal.h
• module.h
• wrappers\corewrappers.h
La librairie WRL
Développement C++#mstechdays
#include "Library1_h.h"
namespace ABI { namespace Library1 {
class Logger : public RuntimeClass<ILogger>
{
InspectableClass(L"Library1.Logger",
BaseTrust)
public:
STDMETHOD(get_Name)(HSTRING* value);
STDMETHOD(put_Name)(HSTRING value);
STDMETHOD(LogInfo)(HSTRING value);
STDMETHOD(GetInt32)(int * pValue);
private:
std::wstring name;
};
ActivatableClass(Logger);
}
}
Un composant WRL Simpleimport "inspectable.idl";
import "Windows.Foundation.idl";
#define COMPONENT_VERSION 1.0
namespace Library1 {
interface ILogger;
runtimeclass Logger;
[uuid(3EC4B4D6-14A6-4D0D-BB96-31DA25224A15),
version(COMPONENT_VERSION)]
interface ILogger : Iinspectable
{
[propget] HRESULT Name([out, retval] HSTRING* value);
[propput] HRESULT Name([in] HSTRING value);
HRESULT LogInfo([in] HSTRING value);
HRESULT GetInt32([out] int * pValue);
}
[version(COMPONENT_VERSION),
activatable(COMPONENT_VERSION)]
runtimeclass Logger
{
[default] interface ILogger;
}
}
Développement C++#mstechdays
#include "Library1_h.h"
class Logger :
public
RuntimeClass<RuntimeClassFlags<ClassicCom>,
ILogger>
{
public:
STDMETHOD(LogInfo)(BSTR value);
};
Un composant COM WRL import "ocidl.idl";
#define COMPONENT_VERSION 1.0
[uuid(3AAF07AA-A699-4E7C-8F01-BFF237D22B1B),
version(COMPONENT_VERSION)]
interface ILogger : IUnknown
{
HRESULT LogInfo([in] BSTR bstrMessage);
}
[uuid(F15D3912-E8B8-40C8-8CF3-354F0B8B93CC),
version(COMPONENT_VERSION)]
library WRLCOMLibrary1
{
[uuid(75DB8F5A-F13F-4E16-A487-9CD26A874654),
version(COMPONENT_VERSION)]
coclass Logger
{
[default] interface ILogger;
}
}
Développement C++#mstechdays
• Attention WRL ne fournit pas de support pour– IDispatch et les interfaces dual, les connections points
– L’enregistrement automatique du module
• Il faut le faire manuellement avec un .reg
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{75DB8F5A-F13F-4E16-A487-9CD26A874654}]
@="Logger Class"
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{75DB8F5A-F13F-4E16-A487-9CD26A874654}\InprocServer32]
@="C:\\dev\\Store\\App1\\Debug\\WRLCOMLibrary1Dll.dll"
"ThreadingModel"="Apartment"
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{75DB8F5A-F13F-4E16-A487-9CD26A874654}\Programmable]
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{75DB8F5A-F13F-4E16-A487-9CD26A874654}\TypeLib]
@="{F15D3912-E8B8-40C8-8CF3-354F0B8B93CC}"
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{75DB8F5A-F13F-4E16-A487-9CD26A874654}\Version]
@="1.0“
WRL et COM
Développement C++#mstechdays
• Exemple de méthode dans la classe Root:
Windows.Foundation.IAsyncOperation<ILogger> GetLoggerAsync();
• Exemple de client XAML C#:
private async void Button_Click(object sender, RoutedEventArgs e)
{
Library1.Root root = new Root();
Library1.ILogger ilogger = await root.GetLoggerAsync();
ilogger.LogInfo("log me !");
}
WRL et les méthodes Async
Développement C++#mstechdays
interface IRoot;
runtimeclass Root;
[uuid(3EC4B4D6-14A6-4D0D-BB96-31DA25224A16), version(COMPONENT_VERSION)]
interface IRoot : IInspectable
{
HRESULT GetLoggerAsync([out][retval] Windows.Foundation.IAsyncOperation<ILogger*>** value);
}
[version(COMPONENT_VERSION), activatable(COMPONENT_VERSION)]
runtimeclass Root
{
[default] interface IRoot;
}
Un composant WRL et les méthodes Async
Développement C++#mstechdays
#include "Library1_h.h"
namespace ABI { namespace Library1 {
class Root : public RuntimeClass<IRoot>
{
InspectableClass(L"Library1.Root", BaseTrust)
public:
STDMETHOD(GetLoggerAsync)(Windows::Foundation::IAsyncOperation<ILogger*>** value);
};
ActivatableClass(Logger);
}
}
• Il faut maintenant implémenter cette interface
• C:\Program Files (x86)\Windows Kits\8.1\Include\winrt
– windows.foundation.collections.h
Le composant WRL avec une méthode Async
Développement C++#mstechdays
namespace ABI { namespace Library1 {
STDMETHODIMP Root::GetLoggerAsync(Windows::Foundation::IAsyncOperation<ILogger*>** value)
{
ComPtr<task_based_async_operation<ILogger>> pObject =
Make<task_based_async_operation<ILogger>>(
std::async([&]() -> ILogger*
{
ComPtr<Logger> p = Make<Logger>();
return p.Detach();
}));
*value = pObject.Detach();
return S_OK;
}
• La magie est contenue dans la classe task_based_async_operation via
PPL Tasks.
La routine GetLoggerAsync()
Développement C++#mstechdays
• Exemple de méthode dans la classe Root:
Windows.Foundation.Collections::IVector<HSTRING> Getvector();
• Exemple de client XAML C#:
private async void Button_Click(object sender, RoutedEventArgs e)
{
Library1.Root root = new Root();
IList<string> list = root.GetVector();
foreach (string s in list) { … }
}
WRL et les Collections
Développement C++#mstechdays
interface IRoot;
runtimeclass Root;
[uuid(3EC4B4D6-14A6-4D0D-BB96-31DA25224A16), version(COMPONENT_VERSION)]
interface IRoot : IInspectable
{
HRESULT GetVector([out][retval] Windows.Foundation.Collections.IVector<HSTRING>** value);
}
[version(COMPONENT_VERSION), activatable(COMPONENT_VERSION)]
runtimeclass Root
{
[default] interface IRoot;
}
Un composant WRL et les collections
Développement C++#mstechdays
#include "Library1_h.h"
namespace ABI { namespace Library1 {
class Root : public RuntimeClass<IRoot>
{
InspectableClass(L"Library1.Root", BaseTrust)
public:
STDMETHOD(GetVector)(Windows::Foundation::Collections::IVector<HSTRING>** value);
};
ActivatableClass(Logger);
}
}
• Il faut maintenant implémenter cette interface
• C:\Program Files (x86)\Windows Kits\8.1\Include\winrt
– windows.foundation.collections.h
Le composant WRL avec les collections
Développement C++#mstechdays
namespace ABI { namespace Library1 {STDMETHODIMP Root::GetVector(Windows::Foundation::Collections::IVector<HSTRING>** value)
{
ComPtr<Vector<HSTRING>> v = Make<Vector<HSTRING>>();
HString str;
str.Set(L"String1");
v->Append(str.Detach());
str.Set(L"String2");
v->Append(str.Detach());
str.Set(L"String3");
v->Append(str.Detach());
*value = v.Detach();
return S_OK;
}
• La magie est contenue dans la classe Vector via std::vector<T>.
La routine GetVector()
Développement C++#mstechdays
• Support en C++/CX via les ‘PPL Taks’
IAsyncOperation<int>^ CalculateAnswer() {
return concurrency::create_async([]() -> int {
// faire une opération longue ici…
return 42; }); }
IAsyncOperation<String^>^ CalculateQuestion() {
return create_async([]() -> String^ {
// faire une opération longue ici…
return ref new String(L“Hello IAsyncOperation<T>…"); }); }
WRL et les opérations asynchrones
Développement C++#mstechdays
CONCLUSION
Développement C++#mstechdays
Juin 2013
Développement C++#mstechdays
C/C++ French user group : [email protected]
Développement C++#mstechdays
Digital is
business