簡體   English   中英

使用set_union和set_intersection時出錯

[英]Error when using set_union and set_intersection

我有兩個集合,我正在嘗試進行並集(進行相交時會遇到相同的錯誤)。 這是錯誤:

error C3892: 'std::_Tree_const_iterator<_Mytree>::operator *' : you cannot assign to a variable that is const

代碼段(如果我用->注釋掉這一行,則代碼會編譯,而我做聯合工作的方法也可以正常工作):

    set<Line *>::iterator it;
    set<Line *> * newSet = new set<Line *>();
    leftLines = pLeft->getSet();
    rightLines = pRight->getSet();
 -->it = set_union(leftLines->begin(),leftLines->end(),rightLines->begin(), rightLines->end(), newSet->begin());
    for(it = leftLines->begin(); it != leftLines->end(); it++)
    {
        newSet->insert(*it);
    }
    for(it = rightLines->begin(); it != rightLines->end(); it++)
    {
        newSet->insert(*it);
    }
    it = newSet->begin();
    while(it != newSet->end())
    {
        result->insert(*it);
        it++;
    }

我敢肯定這有點愚蠢,但我有點迷茫。 我認為該代碼段就足夠了,但是我可以提供所需的任何內容。 謝謝。

這是C ++,不是Java [edit:或.NET]。 您幾乎肯定要替換(例如):

set<Line *> * newSet = new set<Line *>();

只是:

set<Line *> newSet;

...或者,更好的是,可能只是:

set<Line> newSet;

盡管根據您發布的代碼無法確定某些內容,但您的left right也很可能也不應該處理指針-如果它們要執行某種操作,則是一個參考可能更有意義(不過,正如我所說,僅基於您發布的內容,無法確定地說)。

完成此操作后,您將遇到一個小問題: set (或multisetmapmultimap )上的“常規”迭代器實際上是const_iterator。 將某些內容插入關聯容器后,您將無法對其進行更改,因為這可能會破壞集合的不變性(進行排序)。 如果要更改現有項目,則需要從包含中刪除,進行更改,然后將更改的對象重新插入容器。 在您的情況下,您只是插入新項目,因此需要insert_iterator

由於您不打算修改leftright ,因此最好將它們也視為const

std::set_union(left.cbegin(), left.cend(), 
               right.cbegin(), right.cend(), 
               std::inserter(newSet, newSet.end()));

如果決定自己模擬set_union,則可以執行以下操作:

std::set<Line> newSet(left.cbegin(), left.cend());  
std::copy(right.cbegin(), right.cend(), std::inserter(newSet, newSet.end()));

編輯:

通常,您不希望將遍歷器傳遞給容器,而不是傳遞指向容器的指針。 例如,要打印出內容,您現在顯然具有以下內容:

void print_data(std::vector<Line *> const *data) { 
     for (int i=0; i<data->size(); i++)
         std::cout << *(*data)[i] << "\n";
}

它可能具有更多的格式等信息,但是目前我們將忽略這些細節,並假設它是如此簡單。 要直接從您選擇的容器中寫入數據,通常需要一個模板,該模板將接受任意類型的迭代器:

template <class inIt>
void print_data(inIt begin, inIt end) { 
     while (begin != end) 
         std::cout << *begin++ << '\n';
}

但是,我們可以更進一步,並將輸出指定為迭代器:

template <class inIt, class outIt>
void print_data(inIt begin, inIt end, outIt dest) { 
    while (begin != end) {
        *dest++ = *begin++;
        *dest++ = '\n';
    }
}

您可以再走一步,並允許用戶指定要在項目之間使用的分隔符,而不是始終使用'\\ n',但是到那時,您只需要復制標准庫中已經存在的內容- std::copystd::ostream_iterator ,這實際上可能是您要處理的方式:

std::copy(newSet.begin(), newSet.end(), 
          std::ostream_iterator<Line>(std::cout, "\n"));

但是請注意,就標准庫而言, ostream_iterator只是另一個迭代器。 如果您只是要打印出leftright並集,則可以跳過甚至創建一個集合來保存該並集,而直接將其打印出來:

std::set_union(left.cbegin(), left.cend(),
               right.cbegin(), right.cend(), 
               std::ostream_iterator<Line>(std::cout, "\n"));

ostream_iterator寫入文件而不是將其放入普通集合的事實與標准庫完全無關。 它具有一些迭代器類,並且可以將輸出寫入建模正確類的任何迭代器。

現在,可以說,我可能正在大步向前-可能需要在將數據寫入控制台之前對數據進行其他處理。 我的意思不是說您必須將聯合直接寫入標准輸出,而是在打印出來之前不必將其寫入其他集合。

set迭代器不是輸出迭代器。 用這個:

set_union(leftLines->begin(),leftLines->end(),rightLines->begin(), rightLines->end(), inserter(*newSet, newSet->begin()));

另外,為什么要填充newSet 在並集/相交之后保持原樣,否則並集/相交將毫無意義。

set<Line *>::iterator it;
set<Line *> newSet; // No need to `new` this
leftLines = pLeft->getSet();
rightLines = pRight->getSet();
set_union(leftLines->begin(),leftLines->end(),rightLines->begin(), rightLines->end(), inserter(newSet, newSet.begin()));

// Assuming you really need the below code - you could likely just make an inserter directly on `result` instead of the copying.
it = newSet.begin();
while(it != newSet.end())
{
    result->insert(*it);
    it++;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM