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

时间:2013-03-08 12:47:19

标签: c++ cstring

我有一个类需要在构造期间连接两个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*后缀。

怎么做?


BTW。我听说过string。如果我可以使用string,我不会在此问及const char*

7 个答案:

答案 0 :(得分:3)

使用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()的callng const char*获取它。所以在你的情况下,它会给你 c-string "prefix_suffix"

另请注意,您已正确完成声明的顺序:cls必须在 key之后声明,因为其构造取决于key

答案 1 :(得分:2)

使用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未发生变异,const char*返回的c_str()仍然有效。由于intermediateconst,因此不能在其上调用变异函数,因此使用内部缓冲区时cls不应该出现问题。

答案 2 :(得分:1)

您应该使用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,请务必保留声明顺序。

答案 3 :(得分:0)

最好使用std::string将字符串组合在一起。如果需要,您仍然可以致电std::string::c_str()获取const char*std::string::append也以const char*为参数。或者使用+ - 运算符。

请参阅here

答案 4 :(得分:0)

我不确定您是否可以在初始化列表中执行此操作。当然,其他一些有更多经验的用户可以帮助...当然,这听起来很明显但你可以使用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”部分。它在这里代表什么?你想要实现什么目标?。

希望有所帮助。

答案 5 :(得分:0)

我看到两个选项,具体取决于您对价值持续性的需求等。

一,将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;
  }
};

答案 6 :(得分:0)

乍一看,你的问题看起来像是一个理论测验,但后来我回忆起可能有一个没有STL的嵌入式平台。
无论如何,你需要坚持老式的C风格功能:strlen,strcpystrcat
由于您正在使用类,我认为编译器也支持operator 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;
};

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