【问题标题】:Initialize a container that is a private member variable of a class初始化作为类的私有成员变量的容器
【发布时间】:2012-11-07 17:22:11
【问题描述】:

我有一个list<string> myList 作为我班级的私有属性。该列表的内容在编译时是已知的并且是恒定的。是否有任何紧凑的方法(在 C++03 中)来初始化它的值?我只能这么想:

MyClass::MyClass(){
myList.push_back(string("str1"));
myList.push_back(string("str2"));
myList.push_back(string("str3"));
etc.
}

我想要这样的东西:

MyClass::MyClass():list("str1","str2","str3",etc.){
}

【问题讨论】:

  • 你想要的是std::initializer_list,它只在C++11之后才可用。
  • 你可以使用像boost.org/doc/libs/1_52_0/libs/assign/doc/index.html这样的黑客:)
  • 您可以定义一个全局字符串数组并使用列表的两个迭代器构造函数:std::string arr[3] = { "str1", "str2", "str3" }; MyClass::MyClass() : myList(arr, arr+3) { }
  • 不要使用std::list,除非是非常特殊的情况。如果您不知道这些是什么,请不要使用std::list

标签: c++ list initialization initializer c++03


【解决方案1】:

我倾向于做这样的事情:

static const string my_strs[] =
{
  "str1",
  "str2",
  "str3"
};

static const num_my_strs = sizeof(my_strs)/sizeof(my_strs[0]);

然后到时候初始化list:

MyClass::MyClass()
:  myList(my_strs, my_strs + num_my_strs)
{
}

...或:

MyClass::MyClass()
{
  copy( my_strs, my_strs+num_my_strs, back_inserter(myList));
}

这种方法有利有弊。明显的缺点是您现在有 2 个数据副本。这也提出了一个问题,如果您在编译时知道内容并且它们永远不会改变,您甚至需要list 吗?为什么不直接使用static const 数组?

在专业方面,初始化列表的代码是 1-liner,即使您更改正在处理到列表中的编译时常量数据,也永远不需要更改。

编辑:您可以使用标准库算法,如 find 与普通的旧 C 样式数组。例如:

const string* it = std::find(my_strs, my_strs+num_my_strs, "str1");
if( it == (my_strs+num_my_strs) ) // functionally same as 'list.end()' eg, item not found
{ 
  // not found
}
else
{
  // found -- it points to item found
  string found_item = *it;
}

Edit2int a[2]; &a[2]; 这样的表达式是否定义良好正在争论中。我已经编辑了上面的指针数学以使用一种众所周知的不会引起 UB 的方法。

Edit3 我在标准中找到了与此相关的相关段落。上面的表达式 (int a[2]; &a[2];) 实际上是未定义的行为。我已经编辑了我的答案以不使用该方法。感谢@MooingDuck 提出这个问题。

【讨论】:

  • 看起来不错,但是需要两个副本会使我的行数成倍增加。我需要列表,因为它有迭代器,我需要它们在我的列表中调用 std::find(from,to,val)。
  • @user1459339:您知道您可以将标准库算法与我上面的 C 样式数组一起使用吗?事实上,我在第二个例子中就是这样做的,我将copy'ed 从数组到list。您可以轻松地将find 与我的数组一起使用。
  • 我犹豫要否决你,但&my_strs[num_my_strs] UB 不是吗?既然你有一个原始数组,为什么不使用myList(my_strs, my_strs+num_my_strs)
  • @JohnDibling: C++11(Jan2012) §8.3.4\6 “下标运算符[] 被解释为E1[E2]*((E1)+(E2)). 相同”所以@ 987654339@ is 取消引用该指针,因此是 UB。但my_strs+num_my_strs 不是 UB。
  • @JohnDibling:我不知道我可以将算法与 C 样式数组一起使用。谢谢。 +1。请告诉我UB是什么意思?:)
【解决方案2】:

此代码未经过全面测试,但如果您不能使用 C++11 中的新酷东西,我建议您这样做:

class MyClassCreator
{
    MyClass result;
public:
    MyClassCreator(std::string param)
    {
        result.myList.push_back(param);
    }

    MyClassCreator& operator()(std::string param)
    {
        result.myList.push_back(param); 
        return *this;
    }

    operator MyClass() { return result; }

};

用法:

MyClass c = MyClassCreator("object1")("object2")("object3");

编辑

http://ideone.com/LWGRCc查看完整示例

【讨论】:

  • 可爱又聪明,为此我 +1,但我不太在意这一点,并且会射杀任何在生产代码中这样做的程序员。它有点太聪明了,无法维护。
  • @JohnDibling boost 在他们的库中有这个。它可以很好地优化,尤其是在 C++11 中(这很有趣,因为这样你就有了一个更好的方法来通过初始化列表)。虽然是一种“工厂化”的方法,但在生产代码中使用起来还是有点巧妙的。
猜你喜欢
  • 1970-01-01
  • 2016-07-22
  • 2022-01-11
  • 2021-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-18
相关资源
最近更新 更多