简体   繁体   English

在类构造函数中安全地连接c字符串

[英]Safely concatenate c-strings in class constructor

I have a class that needs to concatenate two const char* strings during construction, and even use the result (concatenated string) later on in the initialization list. 我有一个类需要在构造期间连接两个const char*字符串,甚至在初始化列表中使用结果(连接字符串)。

const char* SUFFIX = "suffix";

class widget {
public:
    widget(const char* prefix) : key(???), cls(key) { };

private:
    const char* key;
    const important_class cls;
}

widget("prefix_"); // key should be prefix_suffix

There is a global (in widget 's cpp) const char* suffix that I want to append to user supplied prefix. 有一个全局(在widget的cpp中) const char*后缀,我想附加到用户提供的前缀。

How to do it? 怎么做?


BTW. BTW。 I've heard about string . 我听说过string If I could use string I wouldn't ask here, about const char* 如果我可以使用string我不会在这里问,关于const char*

Using std::string makes your problem a trivial task: 使用std::string会使您的问题成为一项简单的任务:

const std::string SUFFIX = "suffix";

class widget {
public:
    widget(std::string const & prefix) 
           : key(prefix + SUFFIX), cls(key)
    { }       // ^^^^^^^^^^^^^^concatenation!

private:
    const std::string key;
    const important_class cls; 
}

widget("prefix_");

If you need const char* , you could still get it by callng key.c_str() which returns const char* . 如果你需要const char* ,你仍然可以通过key.c_str()获取它,它返回const char* So in your case, it would give you c-string "prefix_suffix" . 所以在你的情况下,它会给你c-string "prefix_suffix"

Also note that the order of declaration is important which you've done correctly : cls must be declared after key as its construction depends on key . 另请注意,声明的顺序非常重要,您已正确完成: cls必须 key 之后声明因为它的构造取决于key

Use std::string as an intermediate value: 使用std::string作为中间值:

const char* SUFFIX = "suffix";

class widget {
public:
    widget(const char* prefix) :
    intermediate(string(prefix) + suffix),
    key(intermediate.c_str()),
    cls(key) {
    }

private:
    const std::string intermediate;
    const char* key;
    const important_class cls;
}

widget("prefix_"); // key should be prefix_suffix

The only thing different to your code here is the private member variable, intermediate . 这里你的代码唯一不同的是私有成员变量, intermediate

The std::string object, intermediate , manages the dynamic memory needed to hold the concatenation. std::string对象( intermediate )管理保持连接所需的动态内存。 It will clean up nicely in the event of exceptions, assignment, copying, etc. 如果出现异常,分配,复制等,它将很好地清理。

As long as the string isn't mutated the const char* returned by c_str() will remain valid. 只要string没有变异, c_str()返回的const char*就会保持有效。 Since intermediate is const , no mutating functions can be called on it, so you shouldn't have problems with cls using the internal buffer. 由于intermediateconst ,因此不能在其上调用变异函数,因此使用内部缓冲区时不应该遇到cls问题。

You should use a std::string (or whatever string class your project uses). 您应该使用std :: string(或项目使用的任何字符串类)。 That would make this much easier and avoid the problems to get this exception-safe. 这将使这更容易,并避免问题,以获得此异常安全。

If you insist, 如果你坚持,

widget(const char* prefix) : 
    key(strcat(strcpy(new char[strlen(prefix)+strlen(SUFFIX)+1], prefix), SUFFIX)), 
    cls(key) { }

would do it the C way. 会这样做的C方式。

The constructor of important_class should not throw exceptions. important_class的构造函数不应抛出异常。

And be careful to keep your order of declarations, if you need to use the resulting key to initialize cls . 如果需要使用生成的key初始化cls ,请注意保持声明顺序。

Better use std::string to put your strings together. 最好使用std::string将字符串放在一起。 You can still call std::string::c_str() to obtain the const char* if needed. 如果需要,您仍然可以调用std::string::c_str()来获取const char* std::string::append takes const char* as argument, too. std::string::appendconst char*作为参数。 Or use + -operator. 或者使用+ -operator。

See here . 看到这里

I am not sure you can do that in initialization lists. 我不确定你能在初始化列表中做到这一点。 Surely some other user with more experience can help there... Of course, this may sound obvious but you can use the std::string and just go: 当然,其他一些有更多经验的用户可以帮助...当然,这听起来很明显但你可以使用std :: string然后去:

class widget 
{
    public:
    widget(const char* prefix) : key(prefix)
    { 
       string_key.append(suffix);
    };

    private:
    const char* key;
    std::string string_key;
};

Of course, you can just do: 当然,你可以这样做:

class widget 
{
    public:
    widget(const char* prefix) : key(prefix)
    { 
       key.append(suffix);
    };

    private:
    std::string key;
};

I am missing the whole "important_class" part. 我错过了整个“important_class”部分。 What does it represent here?. 它在这里代表什么? What are you trying to achieve?. 你想要达到什么目的?

Hope that helps. 希望有所帮助。

I see two options, depending on your needs for value persistency etc. 我看到两个选项,具体取决于您对价值持久性的需求等。

One, store key as a std::string : 一,将key存储为std::string

const char* SUFFIX = "suffix";

class widget{
public:
  widget(const char* prefix) : key(std::string(prefix) + suffix), cls(key.c_str())
  {}

private:
  std::string key;
  const important_class cls;
};

Two, use a static initialisation function, something like this: 二,使用静态初始化函数,如下所示:

const char* SUFFIX = "suffix";

class widget{
public:
  widget(const char* prefix) : key(concat_(prefix, suffix)), cls(key)
  {}

private:
  const char* key;
  const important_class cls;

  static const char* concat_(const char* a, const char* b)
  {
    std::string val(a);
    val += b;
    char* ret = new char[val.size() + 1];
    strcpy(ret, val.c_str());
    return val;
  }
};

At first sight you question looks like a theoretical quiz, but then I recalled there might be an embedded platform without STL. 乍一看,你的问题看起来像是一个理论测验,但后来我回忆起可能有一个没有STL的嵌入式平台。
Anyway you need to stick to the old-school C-style functions: strlen, strcpy and strcat . 无论如何,你需要坚持老式的C风格功能:strlen, strcpystrcat
Since you are using classes, I assume the operator new is also supported by your compiler. 由于您正在使用类,我认为编译器也支持operator new。 Before I write the final code here are the steps you need to undertake to concatenate the strings: 在我编写最终代码之前,您需要采取以下步骤来连接字符串:

const char* key;
key = new char[strlen(prefix) + strlen(SUFFIX) + 1];
strcpy(key, prefix);
strcat(key, SUFFIX);
...
delete [] key;

Luckily both strcpy, and strcat return the destination. 幸运的是strcpy和strcat都返回目的地。
And here is how your code may look: 以下是您的代码的外观:

#include <string.h>

class widget {
public:
  widget(const char* prefix)
    : key(strcat(strcpy(new char[strlen(prefix) + strlen(SUFFIX) + 1], prefix), SUFFIX))
    , cls(key) { };

private:
  const char* key;
  const important_class cls;
};

I didn't debug this code, but it compiles fine, though it looks rather messy... :) 我没有调试这个代码,但它编译得很好,虽然它看起来很混乱...... :)
Don't forget to free the buffer in the destructor. 不要忘记在析构函数中释放缓冲区。
Good luck! 祝好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM