make_unique et cuda

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour à tous,

Je viens quérir votre aide concernant une feature de C++14 qui est : std::make_unique<T>(args); Je travaille sur un projet qui est compilé avec NVCC (Cuda 8.0) et qui doit fonctionner à la fois sur windows et linux. Nous utilisons les std::unique_ptr<T> et avons naïvement commencé à utiliser std::make_unique<T>(args); afin d’instancier nos objets.

Malheureusement, Cuda 8.0 n’autorise qu’au mieux C++11 avec GCC, ce qui ne permet donc pas d’utiliser les std::make_unique. De son coté MSVC s’en sort un peu mieux puisqu’il n’a pas ce flag et permet d’utiliser toutes les features dont il dispose comme bon nous semble. Nous avons alors pensé une "parade" assez simple afin d’avoir une utilisation ressemblant à std::make_unique<T>(args); et qui est create_unique_ptr<T>(args);

Voici l’implémentation :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    template<typename T, typename... Args>
    std::unique_ptr<T> create_unique_ptr(Args... args)
    {
        #if OS == WINDOWS
            return std::make_unique<T>(std::forward<Args>(args)...);
        #elif OS == LINUX
            std::unique_ptr<T> ptr;
            ptr.reset(new T(std::forward<Args>(args)...));
            return ptr;
        #else
            static_assert(false, "OS ??");
        #endif
    }

Tout fier de nous, nous avons continué notre développement sans nous poser de questions et nous étions contents. Et c’est là que les problèmes arrivent, sans s’en rendre compte, utilisée ainsi nous créons une copie des arguments !! Ce qui pose évidemment problème en faisant des copies inutiles mais aussi pour les objets non-copiables. L’idée était alors d’utiliser les références, cependant si elles ne sont pas const le compilateur nous crie dessus (à juste titre) lorsque nous passons des constantes. Il suffirait alors de rajouter const mais vient alors un problème avec std::foward qui ne trouve pas la bonne surcharge lorsque nous faisons appel aux constructeurs par défaut.

Les questions sont donc : Comment arriver à faire tout ça ? Est-ce la meilleur manière de faire ? Pouvons nous faire autrement ? Quel est votre avis ?

Merci à vous !
Cheers

+0 -0

Cette réponse a aidé l'auteur du sujet

L’implémentation type de make_unique est connue pourtant. La solution est dans sa signature : il faut utiliser des forward references ; et dans std::forward() que tu utilises pourtant déjà. Il me semble qu’il y a un article sur le sujet sur ZdS (ou alors, il est juste en préparation?)

PS: pourquoi reset()? (Cf FAQ/application au constructeur)

Édité par lmghs

+1 -0
Auteur du sujet

Ca parait tellement simple…
En fait, je ne cherchais absolument pas ça. J’étais obnubilé par mon template et non pas par l’idée de "remplacer make_unique" donc chercher une implémentation…

PS: pourquoi reset()? (Cf FAQ/application au constructeur)

lmghs

Très bonne question… Jusqu’à ce que tu le pointes cela ne m’avait pas vraiment choqué ! Mais maintenant que tu le dis…

En tout cas, merci beaucoup !

+0 -0

L’utilisation de std::forward sans les références universelles n’a pas beaucoup de sens. Je te conseille de lire (ou relire) "Effective Modern C++", en particulier "Chapter 5 - Rvalue References, Move Semantics, and Perfect Forwarding"

Édité par gbdivers

+1 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte