根据我在几个地方读到的内容,这可能是不可取的(这可能是 std::string 还没有这样做的原因),但在受控环境中并谨慎使用,我认为它编写一个字符串类可能没问题,它可以在第三方库方法需要时隐式转换为适当的可写 char 缓冲区(仅将 char* 作为参数),并且仍然表现得像具有 Find() 等方法的现代字符串, Split(), SubString() 等。虽然我可以稍后尝试实现通常的其他字符串操作方法,但我首先想问一下执行此主要任务的高效和安全方法。目前,我们必须分配一个 char 数组,其大小大约是第三方方法预期的 char* 输出的最大大小,将其传递到那里,然后将返回的 char* 转换为 std::string 以便能够使用它允许的便捷方法,然后使用 string.c_str() 再次将其 (const char*) 结果传递给另一个方法。这既冗长又使代码看起来有点乱。
到目前为止,这是我最初的实现:
MyString.h
#pragma once
#include<string>
using namespace std;
class MyString
{
private:
bool mBufferInitialized;
size_t mAllocSize;
string mString;
char *mBuffer;
public:
MyString(size_t size);
MyString(const char* cstr);
MyString();
~MyString();
operator char*() { return GetBuffer(); }
operator const char*() { return GetAsConstChar(); }
const char* GetAsConstChar() { InvalidateBuffer(); return mString.c_str(); }
private:
char* GetBuffer();
void InvalidateBuffer();
};
MyString.cpp
#include "MyString.h"
MyString::MyString(size_t size)
:mAllocSize(size)
,mBufferInitialized(false)
,mBuffer(nullptr)
{
mString.reserve(size);
}
MyString::MyString(const char * cstr)
:MyString()
{
mString.assign(cstr);
}
MyString::MyString()
:MyString((size_t)1024)
{
}
MyString::~MyString()
{
if (mBufferInitialized)
delete[] mBuffer;
}
char * MyString::GetBuffer()
{
if (!mBufferInitialized)
{
mBuffer = new char[mAllocSize]{ '\0' };
mBufferInitialized = true;
}
if (mString.length() > 0)
memcpy(mBuffer, mString.c_str(), mString.length());
return mBuffer;
}
void MyString::InvalidateBuffer()
{
if (mBufferInitialized && mBuffer && strlen(mBuffer) > 0)
{
mString.assign(mBuffer);
mBuffer[0] = '\0';
}
}
示例用法(main.cpp)
#include "MyString.h"
#include <iostream>
void testSetChars(char * name)
{
if (!name)
return;
//This length is not known to us, but the maximum
//return length is known for each function.
char str[] = "random random name";
strcpy_s(name, strlen(str) + 1, str);
}
int main(int, char*)
{
MyString cs("test initializer");
cout << cs.GetAsConstChar() << '\n';
testSetChars(cs);
cout << cs.GetAsConstChar() << '\n';
getchar();
return 0;
}
现在,我计划在执行任何其他操作之前在几乎所有方法中调用 InvalidateBuffer()。现在我的一些问题是:
- 在内存/性能和/或安全方面是否有更好的方法,尤其是在 C++ 11 中(除了我计划很快添加的常用移动构造函数/赋值运算符)?
- 我最初使用字符的 std::vector 实现了“缓冲区”,这更容易实现并且更像 C++,但担心性能。所以 GetBuffer() 方法只会返回调整大小后的 vector 的起始指针。您认为在这里使用 vector 而不是 char* 有什么主要的优点/缺点吗?
- 我计划稍后为其添加宽字符支持。您认为两个结构的 union :{char,string} 和{wchar_t, wstring} 是否是实现该目的的方法(一次只能是这两个结构之一)?
- 它是否过于矫枉过正,而不是仅仅采用通常的方式传递 char 数组指针,转换为 std::string 并使用它来完成我们的工作。期望 char* 参数的第三方函数调用在代码中大量使用,如果它有效,我计划用这个新字符串完全替换 char* 和 std::string 。
感谢您的耐心等待和帮助!
最佳答案
如果我没理解错的话,你希望它起作用:
mystring foo;
c_function(foo);
// use the filled foo
带有 c_function
喜欢...
void c_function(char * dest) {
strcpy(dest, "FOOOOO");
}
相反,我建议这样做 ( ideone example ):
template<std::size_t max>
struct string_filler {
char data[max+1];
std::string & destination;
string_filler(std::string & d) : destination(d) {
data[0] = '\0'; // paranoia
}
~string_filler() {
destination = data;
}
operator char *() {
return data;
}
};
并像这样使用它:
std::string foo;
c_function(string_filler<80>{foo});
通过这种方式,您可以为 C 函数提供一个“正常”缓冲区,其中包含您指定的最大值(无论哪种方式,您都应该知道……否则调用该函数将是不安全的)。在破坏临时(根据标准,必须在函数调用的表达式之后发生)时,字符串被复制(使用 std::string
赋值运算符)到由 std::string
管理的缓冲区中.
解决您的问题:
Do you think there are any major pros/cons of using a vector instead of char* here?
是的:使用 vector 可以将您从手动内存管理中解放出来。这是一个巨大的优势。
I plan to add wide char support to it later. Do you think a union of two structs : {char,string} and {wchar_t, wstring} would be the way to go for that purpose (it will be only one of these two at a time)?
union 不是个好主意。您如何知道哪个成员当前处于事件状态?你需要在 union 之外有一面旗帜。你真的想让每根绳子都带着它吗?相反,看看标准库在做什么:它使用模板来提供这种抽象。
Is it too much overkill [..]
写一个字符串类? 是的,太多了。
关于c++ - 实现隐式转换为 char* 的 String 类 (C++),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39068844/