Retour de Chaînes à partir des Fonctions de la DLL
Pour une raison quelconque, de retourner une chaîne de caractères à partir d'une fonction de DLL se bloque mon programme sur l'exécution avec l'erreur Unhandled exception at 0x775dfbae in Cranberry Library Tester.exe: Microsoft C++ exception: std::out_of_range at memory location 0x001ef604..
.
J'ai vérifié ce n'est pas un problème avec la fonction elle-même en compilant le code de la DLL comme un .exe
et de faire quelques tests simples dans la main
fonction.
Fonctions avec d'autres types de retour (int
, double
, etc.) le travail parfaitement.
- Pourquoi cela se produit?
- Est-il un moyen de contourner ce problème?
Code Source de la DLL:
//Library.h
#include <string>
std::string GetGreeting();
.
//Library.cpp
#include "Library.h"
std::string GetGreeting()
{
return "Hello, world!";
}
Code Source pour testeur:
//Tester.cpp
#include <iostream>
#include <Library.h>
int main()
{
std::cout << GetGreeting()
}
EDIT: je suis en utilisant VS2010.
Conclusion
Une solution de contournement est de s'assurer que la bibliothèque et la source sont compilés à l'aide de la même compilateur avec le mêmes options, etc.
Mis à jour avec des exemples de code.
Cette compile pour moi dans Visual studio 2008. Quel compilateur que vous utilisez?
Si je comprends bien, si la DLL et EXE sont compilés avec le même compilateur(servicepack et les niveaux de correction) et même des versions de bibliothèques et exactement les mêmes options de compilation, il est possible pour les DLL et EXE pour partager un tas si cela peut fonctionner, toute autre combinaison peut vous donner des problèmes, comme vous le rencontrez
bdk est un excellent point sur les Crt découvrez: msdn.microsoft.com/en-US/library/ms235460(v=VS.80).aspx Bien que cela ne devrait pas être un problème si vous êtes en immeuble deux projets, avec la même version de VS2010 avec la même CRT.
OriginalL'auteur Maxpm | 2010-12-15
Vous devez vous connecter pour publier un commentaire.
Depuis votre message d'erreur vous indique que vous êtes à l'aide de Microsoft C++ je vais vous proposer un MS de réponse spécifique.
Aussi longtemps que vous compilez le fichier EXE et les DLL avec le MÊME compilateur, et à la fois le lien de la MÊME version du moteur d'exécution de manière dynamique, alors vous allez être très bien. Par exemple, à l'aide de "DLL multithread" pour les deux.
Si vous link contre le moteur d'exécution de manière statique, ou un lien à l'encontre de différentes versions du moteur d'exécution puis vous êtes à la SOL pour les raisons @Billy ONeal points (de mémoire seront attribués dans un tas et libéré dans l'autre).
La chaîne est passée par valeur sur la pile, donc une nouvelle chaîne de l'objet doit être créé sur la pile en appelant son constructeur de copie. Que le constructeur peut utiliser des tas de stockage pour le texte, s'il stockées sur la pile, le redimensionnement de la chaîne, plus tard, serait problématique
Que le clarifie. Etrange, il travaille pour une lib statique dans VS2008.
Pour clarifier, la bibliothèque est compilé comme un DLL les mêmes paramètres? Il fonctionne pas si il est compilé comme une bibliothèque statique? Si cela fonctionne, faire les réglages doivent encore être le même?
OriginalL'auteur imaginaryboy
Cela se produit parce que vous êtes de l'allocation de mémoire dans une DLL (en utilisant std::string du constructeur), et de le libérer dans une autre DLL. Vous ne pouvez pas le faire parce que chaque DLL généralement définit son propre tas.
char*
)? Il n'y a vraiment aucun moyen de le faire?si c'est le cas, vous pourriez être en mesure de passer un std::string comme un argument de sortie; par exemple:
void GetGreeting(string& s) { s.assign("Hello World!"); }
Cela peut ou peut ne pas fonctionner, selon la façon dont les allocateurs de piste entre la DLL et non-code de la DLL. Vous voulez essayer de mettre une beaucoup plus grande chaîne, juste pour être sûr.Juste une pensée, serait à l'aide d'un allocateur personnalisé sur le std::les chaînes de caractères qui vit complètement sur un côté de la DLL limites de l'aide? Qui pourrait assurer l'allocation et la libération de mémoire tout se passe de la même tas
Cela devrait fonctionner -- bien sûr, alors il ne serait pas un
std::string
plus que. (Il serait unstd::basic_string<char, std::char_traits<char>, MyAllocatorType>
)Cela ne fonctionnera pas pour les OP cas, le même compilateur / version doivent être utilisés.
OriginalL'auteur Billy ONeal
J'ai eu ce genre de problème qui a été résolu par:
à l'aide de la bibliothèque d'exécution comme DLL de l'application et la DLL (que l'allocation est gérer dans un endroit unique)
s'assurer que tous les paramètres du projet (compilateur, éditeur de liens) sont les mêmes sur les deux projet
OriginalL'auteur patriiice
Mise à jour:
J'ai compilé votre échantillon dans les deux VS2008 et VS2010 et j'ai pu réussir à le compiler et de l'exécuter sans problème. J'ai compilé la bibliothèque, à la fois comme une statique et une dynamique de la bibliothèque.
Original:
Ce qui suit se rapporte à ma discussion avec bdk et imaginaryboy. Je n'ai pas le supprimer comme il peut être de quelque intérêt pour quelqu'un.
Ok cette question vraiment me dérange, parce qu'il semble être passé par valeur et non par référence. Il ne semble pas être les objets créés dans le tas il semble être entièrement à pile.
J'ai fait un test rapide pour vérifier comment les objets sont transmis dans Visual Studio (compilé en mode release, sans lien à l'optimisation du temps et de l'optimisation des handicapés).
Le Code:
Le Démontage:
La Pile:
Pourquoi il s'applique:
Même si le code est dans un autre DLL de la chaîne retournée est copié en valeur dans les appelants pile. Il est caché param qui passe l'objet de
GetGreetings()
. Je ne vois pas du tas se créé. Je ne vois pas le tas ayant rien à voir avec le problème.OriginalL'auteur
Comme snmacdonald j'ai été incapable de reproduire la panne, dans des circonstances normales. Autres déjà mentionnés:
Propriétés de Configuration -> Génération de Code -> Bibliothèque d'Exécution doit être exactement la même
Si je change, je les reçois votre crash. J'ai à la fois la DLL et EXE mis à la DLL multithread.
OriginalL'auteur Adam
Vous pouvez retourner un
std::string
à partir d'une classe aussi longtemps que vous inline la fonction qui crée la chaîne. C'est le cas, par exemple, par la bibliothèque Qt dans leurQString::toStdString
méthode:La fonction en ligne est compilé avec le programme qui utilise la dll, et non pas lorsque la dll est compilé. Cela évite tous les problèmes rencontrés par incompatibles runtimes ou des commutateurs du compilateur.
Donc, en fait, vous ne devriez retourner types standard de votre fichier dll (comme
const char *
etint
ci-dessus) et d'ajouter des fonctions en ligne pour les convertir enstd::string()
.Passant dans un
string &
paramètre peut aussi être dangereux, car ils sont souvent mis en œuvre en tant que copie sur écriture.OriginalL'auteur Mark Beckwith
Comme user295190 et Adam a dit que ça marcherait bien si avec exactement les mêmes paramètres de compilation.
Par exemple, dans Qt QString::toStdString() doit retourner une std::string et vous pouvez l'utiliser dans votre EXE à partir d'QtCore.dll.
Il plante si DLL et EXE a différents paramètres de compilation et la liaison des paramètres. Par exemple, DLL liées aux MD et EXE lié à MT de bibliothèque CRT.
OriginalL'auteur ijab