如何用默认值初始化std:vector of std:vector of fixed length?

时间:2015-05-16 19:26:39

标签: c++ c++11 vector

假设一个包含std :: vector的结构,其项目类型为std :: pair。

struct block {
    std::vector<std::pair<key_t, value_t>> items;
    block(const Data& d) : items()
    {
        items = std::vector<std::pair<key_t, value_t>>(d.size_);
    }
};

稍后在代码中,我为位置0处的向量赋值:

block<key_t, value_t> b(*this);
std::pair<key_t, value_t> item = std::pair<key_t, value_t>(k, v);
b.items[0] = item;

稍后在代码中,我想迭代向量并期望&bucket_item != NULL仅在位置0处为真,因为我只在此位置指定了一个值。事实上,&bucket_item != NULL总是如此。

for (std::pair<key_t, value_t> item : b.items)
{
    if (&item != NULL)
    {
       ...
    }
}

我无法使用NULL值初始化向量,如下所示:

items = std::vector<std::pair<key_t, value_t>>(d.size_, NULL);

如何解决这个问题?

5 个答案:

答案 0 :(得分:3)

看起来你有Java背景,C ++有点不同。

items = std::vector<std::pair<key_t, value_t>>(d.size_);

items已使用其默认构造函数进行初始化。上面的行创建了另一个默认的初始化容器,并将其分配给items,这是不必要的。

在:

b.items[0] = item;

您需要确保向量足够大,因为它不会在operator[]中为您分配元素。可以b.items.push_front/back(item)使用vector::insert将其插入特定位置,例如b.items.insert(b.items.begin(), item)push_xxxinsert会为新元素分配内存。

当你这样做时

for (std::pair<key_t, value_t> item : b.items) 
{
    if (&item != NULL)

迭代容器中的所有现有元素。 item按值(与Java不同)存储在容器中,因此它存在于非NULL地址,并且不能等于NULL

但是,表达式for(std::pair<key_t, value_t> item : b.items)会在堆栈上创建每个元素的副本(也在非NULL地址处),您可能希望for(std::pair<key_t, value_t>& item : b.items)仅引用该元素而不是复制它(注意items左侧的&符号)。如果您不打算在循环内修改item,您可能也希望使用const限定符来向代码的读者明确您的意图。例如for(std::pair<key_t, value_t> const& item : b.items)

因为你无论如何使用C++11,你不必拼出容器元素的类型,只需使用auto

for (auto const& item : b.items) 
    // do something to item

答案 1 :(得分:2)

当您创建std::vector len,其长度为std::vector<T> tVec(len)时,您正在创建一个vector lenT默认构造的T类型对象{1}}。如果要表示空值,则需要采用以下方法之一:

  1. 使用T的标记值表示无效值。
  2. 使用(smart-)pointerT并使用nullptr作为自然无效值。
  3. bool周围打包一个包含struct block { using OptionalPair_t = boost::optional<std::pair<key_t, value_t>>; std::vector<OptionalPair_t> items; block(const Data& d) : items(d.size_) { } }; 标记为无效的课程。
  4. 最后一个选项由boost::optional提供。这是使用它重写代码:

    boost::optional

    由于boolcontextually convertiblefor (auto& item : b.items) { if (item) { ... } } ,您可以这样做:

    import android.app.Activity;
    import android.app.Fragment;
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.support.v4.widget.DrawerLayout;
    import android.support.v7.app.ActionBarDrawerToggle;
    import android.util.Log;
    import android.view.MenuItem;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.ArrayAdapter;
    import android.widget.ListView;
    
    import com.example.example.R;
    
    public class MainActivity extends Activity
    {
        private static final String LOG_TAG = MainActivity.class.getName();
    
        private String[] menuItems;
        private DrawerLayout drawerLayout;
        private ListView drawerList;
        private ActionBarDrawerToggle drawerToggle;
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            if (findViewById(R.id.fragment_container) != null) {
                if (savedInstanceState != null) {
                    return;
                }
    
                menuItems = getResources().getStringArray(R.array.menu_items);
                drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
                drawerList = (ListView) findViewById(R.id.menu);
    
                drawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.menu_list_item, menuItems));
                drawerList.setOnItemClickListener(new DrawerItemClickListener());
    
                drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
    
                drawerToggle = new ActionBarDrawerToggle(
                    this,
                    drawerLayout,
                    R.string.drawer_open,
                    R.string.drawer_close
                ) {
                    public void onDrawerClosed(View view) {
                        super.onDrawerClosed(view);
                        invalidateOptionsMenu();
                    }
    
                    public void onDrawerOpened(View drawerView) {
                        super.onDrawerOpened(drawerView);
                        invalidateOptionsMenu();
                    }
                };
    
                drawerLayout.setDrawerListener(drawerToggle);
    
                getActionBar().setDisplayHomeAsUpEnabled(true);
                getActionBar().setHomeButtonEnabled(true);
    
                LoginFragment loginFragment = new LoginFragment();
                getFragmentManager()
                    .beginTransaction()
                    .replace(R.id.fragment_container, loginFragment).commit();
            }
        }
    
        @Override
        protected void onPostCreate(Bundle savedInstanceState)
        {
            super.onPostCreate(savedInstanceState);
            drawerToggle.syncState();
        }
    
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            drawerToggle.onConfigurationChanged(newConfig);
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item)
        {
            if (drawerToggle.onOptionsItemSelected(item)) {
                return true;
            }
            return super.onOptionsItemSelected(item);
        }
    
        private void selectMenuItem(int position)
        {
            Fragment fragment = null;
            switch (position) {
                case 0:
                    fragment = new DialFragment();
                break;
                case 1:
                    fragment = new NumbersFragment();
                break;
                case 2:
                    fragment = new LoginFragment();
                break;
            }
    
            getFragmentManager()
                .beginTransaction()
                .replace(R.id.fragment_container, fragment)
                .commit();
    
            drawerList.setItemChecked(position, true);
            drawerLayout.closeDrawer(drawerList);
        }
    
        private class DrawerItemClickListener implements ListView.OnItemClickListener
        {
            @Override
            public void onItemClick(AdapterView parent, View view, int position, long id)
            {
                selectMenuItem(position);
            }
        }
    }
    

答案 2 :(得分:0)

我认为你在这里混合了一些定义。 std::vector的元素不能是NULL,因为它不是指针。它的防御性存在。 int arr[] = {1};arr[0]可以为空吗?当然不是。为什么会这样?它是一个真正的整数,它将内存中的某个位置放在非空的位置。

如果你在std :: vector元素上迭代,那意味着它们存在,所以它们不能为空。

答案 3 :(得分:0)

NULL或更好nullptr可用于初始化指针值,但初始化没有任何意义,例如std::stringstd::pair<std::string, int>

如果您希望矢量为空,则可以使用:

std::vector<std::pair<key_t, value_t>> items;

或者,如果您想要n默认构建的std::pair,您可以使用:

std::vector<std::pair<key_t, value_t>> items(n);

答案 4 :(得分:0)

对真的是价值观的结合。因此,您必须定义您认为哪些值组合为您的对的NULL等效值。

然后,您可以使用以下构造函数初始化矢量:

std::vector<std::pair<key_t, value_t>> items(d.size_, make_pair(0,0)) ;

您只需要使用key_t和value_t的中性值替换0。

请注意,向量确实包含值,而对是值。所以没有NULL指针会显示缺少值。