Le C++ a vécu un tel renouveau ces dernières années avec la publication de C++11 (et l'arrivée imminente de C++14) que l'on peut dire qu'il y a une rupture, un avant et un après. Ce changement dans le style de programmation transparait dans chaque ligne de code et se reconnait du premier coup d’œil. À chaque nouvelle version, Visual C++ se rapproche un peu plus du support de la norme, permettant d'écrire du code plus lisible, plus robuste et plus rapide. Plus qu'un simple catalogue des fonctionnalités du langage prises en compte par Visual C++2013, cette présentation a pour ambition de vous montrer, par des exemples concrets, quels bénéfices vous pouvez tirer du C++ moderne. Au détour de ces exemples, on mettra en œuvre la sémantique de déplacement, les fonctions par défaut ou interdites, l'initialisation uniforme, les alias de types... en démasquant quelques pièges à éviter, mais surtout en présentant des pratiques sur lesquels s'appuyer pour apprivoiser ce langage moderne qu'est le C++. On fera enfin un petit point sur l'état d'avancement de Visual C++ par rapport à la norme, et sur la feuille de route présentée par les équipes de développement de Visual C++.
Speakers : Christophe Pichaud (Sogeti), Loïc Joly (Cast)
Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
1.
2. Bonnes pratiques C++11
avec Visual C++
Loïc Joly - CAST
Christophe Pichaud - Sogeti
www.castsoftware.com
www.fr.sogeti.com
Développement C++
3. Donnez votre avis !
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 !
#mstechdays
Développement C++
5. Visual C++ 2013
• 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-a1d290f3f9ef3a09)
– =default, =delete, NSDI, greater<>, make_unique…
• C11 : Meilleur support
– _Bool, déclaration au milieu de bloc, designated
initializer…
• Des retouches d’IHM (formatage du
#mstechdays
Développement C++
6. November 2013 CTP
• 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
#mstechdays
Développement C++
7. GUIDE DE SURVIE EN C++11
Autour de la sémantique de déplacement
#mstechdays
Développement C++
8. Intérêt de déplacer
Copie
Déplacement
• 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
•
•
•
•
•
•
#mstechdays
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
Développement C++
9. Comment ça marche ?
• 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
#mstechdays
Développement C++
10. Comment rendre nos classes déplaçables
• 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 !)
#mstechdays
Développement C++
11. Quelques conseils sur les classes
déplaçables
• 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 !
#mstechdays
Développement C++
12. Utiliser dans l’ordre de préférence
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)
#mstechdays
Développement C++
13. Universal references
• 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)
#mstechdays
Développement C++
14. Transmettre des arguments
La fonction va :
On utilise :
Et pour transmettre:
Utiliser la donnée
Ex: ofstream::open
void f(T const &t);
ou
void 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))
#mstechdays
Développement C++
15. 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…
#mstechdays
Développement C++
18. Pourquoi faire des composants WinRT en C++
Gestion
batterie
Performance
Accès à
Win32
#mstechdays
Protection
contre la
décompilation
Code
existant
Développement C++
19. Scénarios d’applications C++ hybrides
Interface
HTML/JS
Interface
C#/VB
Interface
C++
Composants
WinRT C++
Composants
WinRT C++
Composants
WinRT C#/VB
#mstechdays
Développement C++
20. Le nouveau modèle de composants WinRT
• 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
#mstechdays
Développement C++
21. Un composant WinRT
•
•
•
•
•
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
#mstechdays
Développement C++
22. La librairie WRL
• Les entêtes sont définies dans
– C:Program Files (x86)Windows Kits8.1Includewinrtwrl
• async.h
• client.h
• def.h
• event.h
• ftm.h
• implements.h
• internal.h
• module.h
• wrapperscorewrappers.h
#mstechdays
Développement C++
24. Un composant COM WRL
#include "Library1_h.h"
class Logger :
public
RuntimeClass<RuntimeClassFlags<ClassicCom>,
ILogger>
{
public:
STDMETHOD(LogInfo)(BSTR value);
};
#mstechdays
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++
25. WRL et COM
• 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_ROOTWow6432NodeCLSID{75DB8F5A-F13F-4E16-A487-9CD26A874654}]
@="Logger Class"
[HKEY_CLASSES_ROOTWow6432NodeCLSID{75DB8F5A-F13F-4E16-A487-9CD26A874654}InprocServer32]
@="C:devStoreApp1DebugWRLCOMLibrary1Dll.dll"
"ThreadingModel"="Apartment"
[HKEY_CLASSES_ROOTWow6432NodeCLSID{75DB8F5A-F13F-4E16-A487-9CD26A874654}Programmable]
[HKEY_CLASSES_ROOTWow6432NodeCLSID{75DB8F5A-F13F-4E16-A487-9CD26A874654}TypeLib]
@="{F15D3912-E8B8-40C8-8CF3-354F0B8B93CC}"
[HKEY_CLASSES_ROOTWow6432NodeCLSID{75DB8F5A-F13F-4E16-A487-9CD26A874654}Version]
@="1.0“
#mstechdays
Développement C++
26. WRL et les méthodes Async
• 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 !");
}
#mstechdays
Développement C++
27. Un composant WRL et les méthodes Async
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;
}
#mstechdays
Développement C++
28. Le composant WRL avec une méthode Async
#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 Kits8.1Includewinrt
– windows.foundation.collections.h
#mstechdays
Développement C++
29. La routine GetLoggerAsync()
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.
#mstechdays
Développement C++
30. WRL et les Collections
• 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) { … }
}
#mstechdays
Développement C++
31. Un composant WRL et les collections
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;
}
#mstechdays
Développement C++
32. Le composant WRL avec les collections
#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 Kits8.1Includewinrt
– windows.foundation.collections.h
#mstechdays
Développement C++
33. La routine GetVector()
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>.
#mstechdays
Développement C++
34. WRL et les opérations asynchrones
• 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>…"); }); }
#mstechdays
Développement C++