내 dll 인터페이스 또는 ABI에서 표준 라이브러리 (STL) 클래스를 어떻게 사용할 수 있습니까?
Visual Studio 경고 C4251과 관련하여 stl 클래스를 포함하는 클래스를 내보내기 전에 몇 가지 질문이있었습니다. 예 :이 질문 또는이 질문. 저는 UnknownRoad에서 이미 훌륭한 설명을 읽었습니다.
맹목적으로 경고를 비활성화하는 것은 옵션 일 수 있지만 약간 위험 해 보입니다. 모든 표준 클래스를 래핑하고 내보내는 것도 실제로 옵션이 아닙니다. 결국 표준 템플릿 라이브러리 라고합니다 . 즉, 이러한 표준 클래스와의 인터페이스를 제공하고자합니다.
내 dll 인터페이스에서 stl 클래스를 어떻게 사용할 수 있습니까? 일반적인 관행은 무엇입니까?
더 읽기 전에 한 가지 명심하십시오. 내 대답은 다른 컴파일러에서 컴파일 된 모듈로 구성된 응용 프로그램에서 사용할 수있는 이식 가능한 코드를 작성하는 관점에서 나옵니다. 여기에는 동일한 컴파일러의 다른 버전 또는 다른 패치 수준이 포함될 수 있습니다.
내 dll 인터페이스에서 stl 클래스를 어떻게 사용할 수 있습니까?
답변 : 당신은 자주 할 수없는 일 .
이유 : STL은 DLL과 같은 바이너리 라이브러리가 아니라 코드 라이브러리입니다. 어디에서 사용하든 동일하게 보장되는 단일 ABI가 없습니다. 실제로 STL은 " 표준 템플릿 라이브러리 "의 약자 이지만 여기서 표준 외에 핵심 작동 단어는 템플릿 입니다.
표준은 각 STL 클래스가 제공해야하는 메서드와 데이터 멤버를 정의하고 이러한 메서드가 수행 할 작업을 정의합니다. 그러나 더 이상. 특히 표준은 컴파일러 작성자가 표준 정의 기능을 구현하는 방법을 지정하지 않습니다. 컴파일러 작성자는 표준 에 정의 된 멤버 가 여전히 존재하고 표준이 말하는대로 수행하는 한 표준에 나열 되지 않은 멤버 함수와 멤버 변수를 추가하는 STL 클래스의 구현을 자유롭게 제공 할 수 있습니다 .
예를 들어 보자. basic_string
클래스는 특정 멤버 함수 및 변수를 갖는 것으로 표준에서 정의된다. 실제 정의는 표준에서 거의 4 페이지이지만 다음은 그 일부입니다.
namespace std {
template<class charT, class traits = char_traits<charT>,
class Allocator = allocator<charT> >
class basic_string {
[snip]
public:
// 21.3.3 capacity:
size_type size() const;
size_type length() const;
size_type max_size() const;
void resize(size_type n, charT c);
void resize(size_type n);
size_type capacity() const;
void reserve(size_type res_arg = 0);
void clear();
bool empty() const;
[snip]
};
size()
및 length()
멤버 함수를 고려하십시오 . 이 정보를 보유하기 위해 멤버 변수를 지정한 표준은 없습니다. 실제로, 문자열 자체를 보유하기 위해 정의 된 멤버 변수가 전혀 없습니다. 그렇다면 이것이 어떻게 구현됩니까?
대답은 여러 가지 방법입니다. 일부 컴파일러는 size_t
멤버 변수를 사용 하여 크기 char*
를 보유 하고 a 를 사용하여 문자열을 보유 할 수 있습니다. 다른 하나는 해당 데이터를 보유하는 다른 데이터 저장소에 대한 포인터를 사용할 수 있습니다 (참조 카운트 구현의 경우 일 수 있음). 실제로 동일한 컴파일러의 다른 버전 또는 패치 수준 까지도 이러한 구현 세부 정보를 변경할 수 있습니다. 당신은 그들에게 의지 할 수 없습니다. 따라서 MSVC 10의 구현은 다음과 같습니다.
namespace std {
template<class charT, class traits = char_traits<charT>,
class Allocator = allocator<charT> >
class basic_string {
[snip]
char* m_pTheString;
};
size_t basic_string::size() const { return strlen(m_pTheString;) }
... MSVC 10 SP1은 다음과 같습니다.
namespace std {
template<class charT, class traits = char_traits<charT>,
class Allocator = allocator<charT> >
class basic_string {
[snip]
vector<char> m_TheString;
};
size_t basic_string::size() const { return m_TheString.size(); }
I'm not saying they do look like this, I'm saying they might. The point here is the actual implementation is platform-dependent, and you really have no way of knowing what it will be anywhere else.
Now say you use MSVC10 to write a DLL that exports this class:
class MyGizmo
{
public:
std::string name_;
};
What is the sizeof(MyGizmo)
?
Assuming my proposed implementations above, under MSVC10 its going to be sizeof(char*)
, but under SP1 it will be sizeof(vector<char>)
. If you write an application in VC10 SP1 that uses the DLL, the size of the object will look different than it actually is. The binary interface is changed.
For another treatment of this, please see C++ Coding Standards (Amazon link) issue # 63.
1: "You often can't" You actually can export Standard Library components or any other code library components (such as Boost) with a fair amount of reliability when you have complete control over the toolchains and the libraries.
The fundamental problem is that with source code libraries the sizes and definitions of things can be different between different compilers and different versions of the library. If you are working in an environment where you control both of these things everywhere your code is used, then you probably won't have a problem. For example at a trading firm where all the systems are written in-house and used only in-house, it might be possible to do this.
'program tip' 카테고리의 다른 글
ORM 사용의 장점은 무엇입니까? (0) | 2020.12.06 |
---|---|
종료 후크를 호출하도록 intelliJ에서 실행중인 처리를 어떻게 중지합니까? (0) | 2020.12.05 |
Firefox가 이미지 크기 조정에 왜 그렇게 나쁜가요? (0) | 2020.12.05 |
pimpl에 unique_ptr을 어떻게 사용합니까? (0) | 2020.12.05 |
GPL / LGPL 및 정적 연결 (0) | 2020.12.05 |