Boost FOR_EACH Over A Ptr_Vector? - c++

I'm currently having fun trying to learn some of the Boost libary. I'm currently doing what I guess will be a future homework project (semester hasn't started yet). However, this question is not about the homework problem, but about Boost.
Code:
/* AuctionApplication.h */
class AuctionApplication : boost::noncopyable
{
private:
boost::ptr_vector<Auction> auctions_;
boost::ptr_vector<Bidder> bidders_;
boost::ptr_vector<Bid> bids_;
/* AuctionApplication.cpp */
Bid *AuctionApplication::GetLatestBid(const Auction *auction)
{
Bid *highestBid = 0;
BOOST_FOREACH(Bid *bid, bids_) // Error here!
if (bid->GetAuction()->GetName() == auction->GetName())
highestBid = bid;
BOOST_FOREACH use to work with normal vectors with the exact same code as above. Since I've started using ptr_vectors I get the error:
error C2440: '=' : cannot convert from 'Bid' to 'Bid *'
Leading me to believe that ptr_vector somehow obscures the pointer from the foreach method.
If I instead write
BOOST_FOREACH(Bid *bid, bids_)
I get four errors of the type
error C2819: type 'Bid' does not have an overloaded member 'operator ->'
which sucks, because I know bid is a pointer.
How can I make BOOST_FOREACH iterate properly over the ptr_vectors?

ptr_vector takes ownership of heap allocated objects and presents each object as a reference so you don't need dereferencing and you use . instead of -> to access member variables/functions. e.g.
Bid highestBid = 0;
BOOST_FOREACH (Bid& bid, bids_)
if (bid.GetAuction()->GetName() == auction->GetName())
highestBid = &bid;

Related

Was it possible to get a pointer to member from an instance of an object?

I was porting some legacy code to VS 2015 when this compiler error halted the build:
error C3867: 'OptDlg::GetFullModel': non-standard syntax; use '&' to create a pointer to member
Going to the corresponding file and line, I saw this:
Manager mgr = GetDocument()->GetManager();
OptDlg dlg;
...
mgr->SetFullModel(dlg.GetFullModel);
if ( dlg.GetFullModel )
mgr->SetSymm(...
GetFullModeland SetFullModel are the getter/setter pair for a member variable in two different classes:
class Manager {
...
bool GetFullModel() { return m_bFullModel; }
void SetFullModel(bool bFlag) { m_bFullModel = bFlag; }
....
};
class OptDlg {
...
void GetFullModel() { return m_bFullModel; }
void SetFullModel(bool bValue) { m_bFullModel = bValue; if ( bValue ) m_bInside = 0;}
Yep, something's wrong. Was dlg.GetFullModel supposed to be a pointer to a member function? I thought those use the class name, not an instance. Not to mention what that would mean for execution semantics...
C++ is still relatively new to me, so I tried Google. It had a lot on function pointers, but they all looked different from what I had:
&OptDlg::GetFullModel // Standard-compliant
vs
OptDlg::GetFullModel // The "normal" way to mess up getting a pointer to member, it seems
vs
dlg.GetFullModel // ?
Is dlg.GetFullModel just another way of getting a pointer to member function? If not, what is the "standard C++ version", if there is one? Is this just another one of those VS 6 "extensions"?
&OptDlg::GetFullModel // Standard-compliant
If your parameter types were supposed to be taking member functions, that's what you'd use. But they take booleans. It looks like you're just missing parentheses on your function calls, and it should be:
mgr->SetFullModel(dlg.GetFullModel());
if (dlg.GetFullModel())
mgr->SetSymm(...
Probably someone was ignoring warnings (or didn't have them on) and hence a pointer value (being produced through whatever shady means) was always being interpreted as non-NULL, hence boolean true.
Is this just another one of those VS 6 "extensions"?
It would appear to be the case, although this comment is the only documented evidence I can find it was an intentional/advertised "feature". Don't see any formal announcement of it being added or taken out.
It strongly looks to me like someone mis-typed dlg.GetFullModel() (which would call the function), not that they were trying to get a member function pointer.
Presumably the legacy compiler let it slide, taking the address of the function without using & and converting the non-null function pointer to bool (with value true) to pass into the set function.

Method returning std::vector<std::unique_ptr<Object>>

As a continuation of a: Thread, I came across a problem with
writing a method of a class which returns:
std::vector<std::unique_ptr<Object>>
I get compiler errors when such a return type is written. There is some problem with delete operand or something ...
Generally, I've wanted to write a method which initializes vector and returns it.
Could anyone help me how to write it?
EDIT:
I Get:
attempting to reference a deleted function h:\pliki programów (x86)\microsoft visual studio 12.0\vc\include\xmemory0
Here I have the following code snippet. Can I create such a method like this?
std::vector<std::unique_ptr<Object>> Class::TestMethod(int param)
{
std::vector<std::unique_ptr<Object>> array;
auto day = std::make_unique<Object>();
array.push_back(day);
return array;
}
Your error is actually coming from:
array.push_back(day);
This tries to put a copy of day in the vector, which is not permitted since it is unique.
Instead you could write array.push_back( std::move(day) ); however the following would be better, replacing auto day...:
array.emplace_back();
The copy constructor of std::unique_ptr is deleted. That causes a problem in the line:
array.push_back(day);
Use
array.push_back(std::move(day));

Creating an auto_ptr with 2 arguments

Hi I have a compile error when I run this code:
std::auto_ptr<MyDisplay> m_display =
std::auto_ptr<MyDisplay>(new MyDisplay(this, m_displayController));
The error is this one:
error C2664: 'MyDisplay::MyDisplay(DemoWindow *,DisplayController*)':
cannot convert parameter 2 from 'std::auto_ptr<_Ty>' to 'DisplayController*'
However when I pass only one argument the code is correct:
std::auto_ptr<DisplayController> m_displayController =
std::auto_ptr<DisplayController>(US_NEW(DisplayController, this));
What is the proper way to create the pointer in the auto_ptr with 2 arguments?
From the error message, it appears that m_displayController is an std::auto_ptr<DisplayController>, while the MyDisplay constructor expects a DisplayController*.
Try :
std::auto_ptr<MyDisplay> m_display =
std::auto_ptr<MyDisplay>(new MyDisplay(this, m_displayController.get()));
or better yet, make the constructor compatible with std::auto_ptr<DisplayController>.
As an aside : the choice of std::auto_ptr here is probably not the best. You might want to read up on the different types of smart pointers, and the different behaviors they have.
I'd like to clarify your idea of creating the auto pointer, which I hope will help.
Your goal here is to create an auto_ptr holding a DisplayController*. You could write
m_displayController = std::auto_ptr<DisplayController>( new DisplayController(x, y) );
Or have a function that returns a pointer, like this :
m_displayController = std::auto_ptr<DisplayController>( US_NEW(x,y) );
You can check out a simple example here.

c++ attempting to reference deleted function

I have been playing around with std::unique_ptr and the std::for_each algorithm to learn them and I then received this error "attempting to reference a deleted function" when I am attempting to move some variables from one container (std::map) to another.
This code is currently executed in a member function. Foo is just a generic class.
std::for_each(m_list1.begin(), m_list1.end(),
[&](std::pair<std::size_t,std::unique_ptr<Foo>> data_pair)
{
m_list2[data_pair.first] = std::unique_ptr<Foo>(std::move(data_pair.second));
});
m_list1.clear();
I tried various things but the problems still persists. I then tried using range-based for instead and suddenly it works.
for (auto& data_pair : m_list1)
{
m_list2[data_pair.first] = std::unique_ptr<Foo>(std::move(data_pair.second));
}
m_list1.clear();
What I want to know is why the second code executed with no problem, while the first code produced the error.
If you need more specific information, Just ask. If there's bad practice in my coding style, please advice on how to make it better.
There are two errors in your for_each code. First, map::value_type is pair<const Key, Value>. Second, your lambda expression is taking the argument by value, which means it attempts to copy the unique_ptr, hence the error. To fix it, take the argument by reference.
[&](std::pair<const std::size_t, std::unique_ptr<Foo>>& data_pair)
// ^^^^^ ^^^
{
m_list2[data_pair.first] = std::unique_ptr<Foo>(std::move(data_pair.second));
}
A better option is to not mention those types explicitly, instead use decltype
[&](decltype(m_list1)::value_type& data_pair)
{
m_list2[data_pair.first] = std::unique_ptr<Foo>(std::move(data_pair.second));
}
Now, your range-based for worked because you were binding the elements of the map to a reference by using for(auto& data_pair : m_list1). You'd have run into the same error as before if you'd instead used for(auto data_pair : m_list1) because that'd have attempted to make a copy of the elements.

C++ Linked List Error: lvalue required as left operand of assignment

Alright, I'm trying to write a program in C++ that deals with a double-linked list. Specifically, the list contains a collection of artwork objects as its nodes. In this particular function, I'm trying to remove nodes through the "sell" command, but I'm getting this error on several lines:
Error: lvalue required as left operand of assignment
I've done my research and I've found that this type of error commonly arises when you try to assign values when you actually want to compare them, or if you're trying to assign values to a constant. However, I don't think that's my problem. Here's the problem code:
// Sell At Function: This function sells the specified artwork.
void CR_ArtCollection::sell_at(string title, ostream& log)
{
CR_ArtWorks* walker = first;
while(walker != NULL)
{
if(title == walker->get_title())
{
walker->get_next()->get_prev() = walker->get_prev(); // Error
walker->get_prev()->get_next() = walker->get_next(); // Error
delete walker;
walker = NULL;
}
else walker = walker->get_next();
}
}
If anyone can point me in the right direction, I would be incredibly appreciative.
It's quite obvious - get_prev and get_next return r-values. That means you can't assign to them.
Check your interface for a method similar to set_next and set_prev and call it as:
walker->get_next()->set_prev(walker->get_prev());
walker->get_prev()->set_next(walker->get_next());
As the names suggest - get_xxxx, those methods are there so you can get the values, not also set them.
Alright, if a function returns a primitive type such as a integer or a pointer it is not legal to assign to the result of the function. That's the error you have.
One possibility would be to change your get_prev and get_next function to return references to pointers.
But I don't suggest you do that. Your code clearly needs redesigning. You should add an erase function to your linked list class. That way the pointer manipulation code will be in the CR_ArtWorks class where it belongs, instead of the CR_ArtCollection class where it doesn't.