位于外部 DLL 中的 class 中 wstring 数据的内存损坏
Memory corruption of wstring data in class placed in external DLL
目标
将字符串数据存储在 classes 中放置在外部 DLL 中。
使用的指南
Create and use your own Dynamic Link Library
环境
- Microsoft Visual Studio Community 2017,版本 15.6.4
- Windows 10 专业版 x64
为什么这个问题是独一无二的?
其他 QA 也在谈论 DLL 或 classes,但 none 处理外部 DLL classes 中的字符串主题。
描述
我在 DLL 中使用容器 classes(classes 的目的是保存数据)中的字符串时遇到了问题。从我的角度来看,记忆位置似乎出了问题。
我从 Internet 了解到在 DLL 中不能轻易使用 wstring
(或 string
),而应该使用指针(const wchar_t*
) .
然而,即使这样做,如果我稍微传递它们,对象中字符串中的数据似乎也会损坏。
我怎么
- 放置和检索字符串数据...
- to/from class 会员...
- 在 DLL 中...
- 没有数据丢失或损坏?
密码
DLL中的头文件:
// AnimalLibrary.h - Contains declarations of animal methods.
#pragma once
#ifdef ANIMALLIBRARY_EXPORTS
#define ANIMALLIBRARY_API __declspec(dllexport)
#else
#define ANIMALLIBRARY_API __declspec(dllimport)
#endif
class Animal {
public:
ANIMALLIBRARY_API static Animal* GetAnimal();
virtual ~Animal() = 0;
virtual void SetSound(const wchar_t* sound) = 0;
virtual wchar_t const* GiveSound() const = 0;
virtual Animal* clone() const = 0;
};
DLL 主体:
// AnimalLibrary.cpp : Defines the exported functions for the DLL application.
#include "stdafx.h"
#include "AnimalLibrary.h"
#include <string>
using namespace std;
Animal* Animal::GetAnimal() {
class RealAnimal :public Animal {
public:
void SetSound(wchar_t const* sound) override {
this->sound = sound;
}
wchar_t const* GiveSound() const override {
return sound.c_str();
}
Animal* clone() const override {
return new RealAnimal{ *this };
}
private:
wstring sound;
};
return new RealAnimal{};
}
Animal::~Animal() = default;
最后是应用程序本身:
// StringInDllClass.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "AnimalLibrary.h"
#include <iostream>
#include <string>
#include <memory>
using namespace std;
int main();
void printMessage(unique_ptr<Animal> animal);
unique_ptr<Animal> createCow();
wstring createCowSound();
int main()
{
unique_ptr<Animal> cow = createCow();
//This row won't compile due to
//error C2280: attempting to reference a deleted function:
//'unique_ptr<Animal,default_delete<_Ty>>::unique_ptr(
//const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)'
printMessage(cow);
system("pause");
return 0;
}
void printMessage(unique_ptr<Animal> animal) {
wcout << L"The animal says " << animal->GiveSound() << endl;
}
unique_ptr<Animal> createCow() {
unique_ptr<Animal> cow{ Animal::GetAnimal() };
cow->SetSound(createCowSound().c_str());
return cow;
}
wstring createCowSound() {
return L"Moo";
}
以与在源库中相同的方式在外部 DLL 中放置和检索字符串数据 to/from class 成员。
我看到 header 定义正确,只是不要忘记在源库中设置 ANIMALLIBRARY_EXPORTS,而不是目标库。
我相信你得到字符串损坏的原因是指向局部变量的指针被重新调整,并且局部变量在离开作用域时被破坏,所以指针无效
Animal createCow() {
Animal cow;
wstring sound = createCowSound(); //sound is local varialbe
cow.Sound = sound.c_str(); //here you set pointer to local variable
return cow;
} //local variable is destroyed here
要解决此问题,请在 Animal class 中提供 operator=
,以复制由 'const wchar_t* Sound;' 指针指向的 object,或替换 const wchar_t* Sound;
由 wstring Sound;
在动物 class.
这是一个使用继承的准系统实现,这避免了跨 dll 边界传递潜在的不安全类型,同时允许您在 dll 本身内部使用标准库类型。您也可以使用 pimpl 习语实现同样的效果。
AnimalLibrary.h
#pragma once
class Animal
{
public:
__declspec(dllexport) static Animal* getAnimal();
virtual ~Animal() =0;
virtual void setSound(wchar_t const* name) =0;
virtual wchar_t const* getSound() const =0;
virtual Animal* clone() const =0;
};
AnimalLibrary.cpp
#include "AnimalLibrary.h"
#include <string>
Animal* Animal::getAnimal()
{
class RealAnimal : public Animal
{
public:
void setSound(wchar_t const* name) override
{
sound = name;
}
wchar_t const* getSound() const override
{
return sound.c_str();
}
Animal* clone() const override
{
return new RealAnimal{*this};
}
private:
std::wstring sound;
};
return new RealAnimal{};
}
Animal::~Animal() =default;
test.cpp
#include <iostream>
#include <memory>
#include "AnimalLibrary.h"
int main()
{
std::unique_ptr<Animal> cow{Animal::getAnimal()};
cow->setSound(L"moo");
std::wcout << cow->getSound();
decltype(cow) dog{cow->clone()};
dog->setSound(L"woof");
std::wcout << dog->getSound();
}
目标
将字符串数据存储在 classes 中放置在外部 DLL 中。
使用的指南
Create and use your own Dynamic Link Library
环境
- Microsoft Visual Studio Community 2017,版本 15.6.4
- Windows 10 专业版 x64
为什么这个问题是独一无二的?
其他 QA 也在谈论 DLL 或 classes,但 none 处理外部 DLL classes 中的字符串主题。
描述
我在 DLL 中使用容器 classes(classes 的目的是保存数据)中的字符串时遇到了问题。从我的角度来看,记忆位置似乎出了问题。
我从 Internet 了解到在 DLL 中不能轻易使用 wstring
(或 string
),而应该使用指针(const wchar_t*
) .
然而,即使这样做,如果我稍微传递它们,对象中字符串中的数据似乎也会损坏。
我怎么
- 放置和检索字符串数据...
- to/from class 会员...
- 在 DLL 中...
- 没有数据丢失或损坏?
密码
DLL中的头文件:
// AnimalLibrary.h - Contains declarations of animal methods.
#pragma once
#ifdef ANIMALLIBRARY_EXPORTS
#define ANIMALLIBRARY_API __declspec(dllexport)
#else
#define ANIMALLIBRARY_API __declspec(dllimport)
#endif
class Animal {
public:
ANIMALLIBRARY_API static Animal* GetAnimal();
virtual ~Animal() = 0;
virtual void SetSound(const wchar_t* sound) = 0;
virtual wchar_t const* GiveSound() const = 0;
virtual Animal* clone() const = 0;
};
DLL 主体:
// AnimalLibrary.cpp : Defines the exported functions for the DLL application.
#include "stdafx.h"
#include "AnimalLibrary.h"
#include <string>
using namespace std;
Animal* Animal::GetAnimal() {
class RealAnimal :public Animal {
public:
void SetSound(wchar_t const* sound) override {
this->sound = sound;
}
wchar_t const* GiveSound() const override {
return sound.c_str();
}
Animal* clone() const override {
return new RealAnimal{ *this };
}
private:
wstring sound;
};
return new RealAnimal{};
}
Animal::~Animal() = default;
最后是应用程序本身:
// StringInDllClass.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "AnimalLibrary.h"
#include <iostream>
#include <string>
#include <memory>
using namespace std;
int main();
void printMessage(unique_ptr<Animal> animal);
unique_ptr<Animal> createCow();
wstring createCowSound();
int main()
{
unique_ptr<Animal> cow = createCow();
//This row won't compile due to
//error C2280: attempting to reference a deleted function:
//'unique_ptr<Animal,default_delete<_Ty>>::unique_ptr(
//const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)'
printMessage(cow);
system("pause");
return 0;
}
void printMessage(unique_ptr<Animal> animal) {
wcout << L"The animal says " << animal->GiveSound() << endl;
}
unique_ptr<Animal> createCow() {
unique_ptr<Animal> cow{ Animal::GetAnimal() };
cow->SetSound(createCowSound().c_str());
return cow;
}
wstring createCowSound() {
return L"Moo";
}
以与在源库中相同的方式在外部 DLL 中放置和检索字符串数据 to/from class 成员。
我看到 header 定义正确,只是不要忘记在源库中设置 ANIMALLIBRARY_EXPORTS,而不是目标库。
我相信你得到字符串损坏的原因是指向局部变量的指针被重新调整,并且局部变量在离开作用域时被破坏,所以指针无效
Animal createCow() {
Animal cow;
wstring sound = createCowSound(); //sound is local varialbe
cow.Sound = sound.c_str(); //here you set pointer to local variable
return cow;
} //local variable is destroyed here
要解决此问题,请在 Animal class 中提供 operator=
,以复制由 'const wchar_t* Sound;' 指针指向的 object,或替换 const wchar_t* Sound;
由 wstring Sound;
在动物 class.
这是一个使用继承的准系统实现,这避免了跨 dll 边界传递潜在的不安全类型,同时允许您在 dll 本身内部使用标准库类型。您也可以使用 pimpl 习语实现同样的效果。
AnimalLibrary.h
#pragma once
class Animal
{
public:
__declspec(dllexport) static Animal* getAnimal();
virtual ~Animal() =0;
virtual void setSound(wchar_t const* name) =0;
virtual wchar_t const* getSound() const =0;
virtual Animal* clone() const =0;
};
AnimalLibrary.cpp
#include "AnimalLibrary.h"
#include <string>
Animal* Animal::getAnimal()
{
class RealAnimal : public Animal
{
public:
void setSound(wchar_t const* name) override
{
sound = name;
}
wchar_t const* getSound() const override
{
return sound.c_str();
}
Animal* clone() const override
{
return new RealAnimal{*this};
}
private:
std::wstring sound;
};
return new RealAnimal{};
}
Animal::~Animal() =default;
test.cpp
#include <iostream>
#include <memory>
#include "AnimalLibrary.h"
int main()
{
std::unique_ptr<Animal> cow{Animal::getAnimal()};
cow->setSound(L"moo");
std::wcout << cow->getSound();
decltype(cow) dog{cow->clone()};
dog->setSound(L"woof");
std::wcout << dog->getSound();
}