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

wooyq4lh  于 2023-04-08  发布在  其他
关注(0)|答案(8)|浏览(99)

我有一个类,它需要在构造过程中连接两个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

有一个全局(在widget的cpp中)const char*后缀,我想将它附加到用户提供的前缀上。
怎么做?

**顺便说一句。**我听说过string。如果我可以使用string,我不会在这里问,关于const char*

2skhul33

2skhul331#

使用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_");

如果你需要const char*,你仍然可以通过调用key.c_str()来得到它,它返回const char*。所以在你的例子中,它会给予你 c-string"prefix_suffix"
还要注意,声明的顺序很重要,你已经正确地做到了:cls必须在 * key之后声明,因为它的构造依赖于key

k75qkfdt

k75qkfdt2#

使用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

这里与您的代码唯一不同的是私有成员变量intermediate
std::string对象,intermediate,管理保存连接所需的动态内存。在发生异常、赋值、复制等情况时,它会很好地清理。
只要string没有发生突变,c_str()返回的const char*就仍然有效。由于intermediateconst,因此不能在其上调用任何突变函数,因此使用内部缓冲区的cls应该不会有问题。

6za6bjd0

6za6bjd03#

你应该使用std::string(或者你的项目使用的任何字符串类)。这会使这更容易,并避免获得异常安全的问题。
如果你坚持

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

我会用C的方式。
important_class的构造函数不应该抛出异常。
如果需要使用结果key初始化cls,请注意保持声明的顺序。

31moq8wy

31moq8wy4#

最好使用std::string将字符串放在一起。如果需要,您仍然可以调用std::string::c_str()来获取const char*std::string::append也将const char*作为参数。或者使用+-operator。
参见here

nhn9ugyo

nhn9ugyo5#

我不确定你能在初始化列表中做到这一点。当然,其他一些有更多经验的用户可以帮助你......当然,这听起来很明显,但是你可以使用std::string,然后执行以下命令:

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

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

当然,你可以这样做:

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

    private:
    std::string key;
};

我错过了整个“important_class”部分。它在这里代表什么?。你想达到什么目的?。
希望能帮上忙。

vlju58qv

vlju58qv6#

我看到了两个选项,这取决于您对值持久性等的需求。
第一,将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;
};

第二,使用一个静态初始化函数,类似这样:

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;
  }
};
jhkqcmku

jhkqcmku7#

乍一看,你的问题看起来像一个理论测验,但后来我想起可能有一个没有STL的嵌入式平台。
无论如何,你需要坚持使用老式的C风格函数:strlen、strcpystrcat
因为你使用的是类,我假设你的编译器也支持new运算符。在我写最后的代码之前,这里是你需要执行的连接字符串的步骤:

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

幸运的是,strcpy和strcat都返回了目的地。
下面是你的代码可能看起来的样子:

#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;
};

我没有调试这段代码,但它编译得很好,虽然看起来很混乱...:)
不要忘记释放析构函数中的缓冲区。
祝你好运!

lawou6xi

lawou6xi8#

如果你不是std::string的粉丝,你仍然可以使用c风格的char* builder自定义函数,并在构造函数中调用builder。
在下面的示例中,父类std::runtime_error(const char*)已从其子类成功初始化,
你可以在孩子和父母之间发现任何错误:
num::dividebyzero_error
std::runtime_error
std::exception
在任何情况下,err.what()都能正确显示字符串。

// snprintf(char* result, size_t maxsize, const char* format, args...)
#include <iostream>
class num {
public:
    int value;
    num() : value(0) {}
    num(int newvalue) : value(newvalue) {}
    class dividebyzero_error : public std::runtime_error {
    private:
        const char* makemsg(int dividend) {
            char* msg = (char*)malloc(128);
            snprintf(msg, 128, "You should not divide %d into ZERO.", dividend);
            return msg;
        }
    public:
        dividebyzero_error(int dividend): std::runtime_error(makemsg(dividend)) {} // this works!
    };
    friend num operator/(const num &n1, const num &n2) {
        if (n2.value == 0) throw dividebyzero_error(n1.value);
        return num(n1.value / n2.value);
    }
};
int main() {
    num a(1234);
    num b;
    try {
        num c = a / b;
        std::cout << c.value << '\n';
    } catch (std::exception &err) {
        std::cout << err.what() << '\n';
    }
}

相关问题