The problem:
#include <iostream>
#include <algorithm>
using namespace std;
struct abc
{
int cost;
int any;
};
int main() {
abc *var1 = new abc[5];
var1[0].cost = 4;
var1[1].cost = 42;
var1[2].cost = 5;
var1[3].cost = 0;
var1[4].cost = 12;
// cout<< "value = " << *std::min_element(var1.cost,var1.cost+5) << endl;
// cout << "Position = " << (std::min_element(var1.cost,var1.cost+5)-var1.cost) << endl;
return 0;
}
How to find minimum value and position of var1[].cost? is it possible to find this using std::min_element?
std::min_element - cppreference.com
You can use a comparision function object to have std::min_element look at the member cost.
#include <iostream>
#include <algorithm>
using namespace std;
struct abc
{
int cost;
int any;
};
struct cmp_abc {
bool operator()(const abc& a, const abc& b) const {
return a.cost < b.cost;
}
};
int main() {
abc *var1 = new abc[5];
var1[0].cost = 4;
var1[1].cost = 42;
var1[2].cost = 5;
var1[3].cost = 0;
var1[4].cost = 12;
abc *res = std::min_element(var1, var1 + 5, cmp_abc());
cout << "value = " << res->cost << endl;
cout << "Position = " << (res - var1) << endl;
delete[] var1;
return 0;
}
I can think of at least four ways to do this with std::min_element
1) Add a "less than" member function to the struct/class:
struct abc
{
int cost;
int any;
bool operator<(const abc &other) const { // member function
return cost < other.cost;
}
};
int main() {
// ...
// The algorithm will find and use the class operator< by default
abc *ptr = std::min_element(var1, var1 + 5);
}
2) Define a free function:
bool abc_less(const abc &lhs, const abc &rhs) // free function
{
return lhs.cost < rhs.cost;
}
int main() {
// ...
// Pass a function pointer to the algorithm
abc *ptr = std::min_element(var1, var1 + 5, abc_less);
}
3) Define a function object type:
struct abc_less // function object
{
bool operator()(const abc &lhs, const abc &rhs) const {
return lhs.cost < rhs.cost;
}
};
int main() {
// ...
// Construct and pass a function object to the algorithm
abc *ptr = std::min_element(var1, var1 + 5, abc_less());
}
4) Create a lambda function:
int main() {
// ...
// Create a lambda at the point of call in this example
abc *ptr = std::min_element(var1, var1 + 5, [](const abc &lhs, const abc &rhs) { return lhs.cost < rhs.cost; });
}
Finally, use the returned iterator (pointer in this case) to print the value or offset:
std::cout << "Value = " << ptr->cost << '\n';
std::cout << "Position = " << (ptr - var1) << '\n'; // or std::distance(var1, ptr)
Related
I have written a program which was given to me as a homework assignment (it's a bit longer). The issue is that it compiles in CodeBlocks but it does not compile in Visual Studio 2017 it says - binary '=': no operator found which takes a right-hand operand of type 'CAutomobile' (or there is no acceptable conversion.
I would like to ask why is that because I could not myself find the error? I tried commenting the operator =function but still the error remained.
#include <iostream>
#include <algorithm>
#include <string>
#include <stdlib.h>
using namespace std;
class CVehicle {
string name;
int year;
public:
CVehicle() {
name = "Car";
year = 1990;
}
CVehicle(string n, int y) {
name = n;
year = y;
}
CVehicle(const CVehicle& vc) {
name = vc.name;
year = vc.year;
}
void setName(string n) {
name = n;
}
void setYear(int y) {
year = y;
}
string getName() {
return name;
}
int& getYear() {
return year;
}
virtual void Print(ostream& os) = 0;
};
class CAutomobile :public CVehicle {
double litres;
public:
CAutomobile() :CVehicle() {
litres = 7.2;
}
CAutomobile(string nm, int yr, double l) :CVehicle(nm, yr) {
litres = l;
}
void setLitres(double l) {
l = litres;
}
double& getLitres() {
return litres;
}
void Print(ostream& os) override {
os << getName() << endl;
os << getYear() << endl;
os << litres << endl;
}
friend bool operator< (CAutomobile a1, CAutomobile a2) {
if (a1.litres < a2.litres) {
return true;
}
return false;
}
CAutomobile operator= (CAutomobile& at) {
CAutomobile au;
au.getName() = at.getName();
au.getYear() = at.getYear();
au.getLitres() = at.getLitres();
return au;
}
CAutomobile operator+(CAutomobile aut) {
CAutomobile a;
a.getLitres() = getLitres() + aut.getLitres();
return a;
}
friend ostream& operator<< (ostream& o, CAutomobile a) {
o << a.getName() << endl;
o << a.getYear() << endl;
o << a.getLitres() << endl;
return o;
}
};
int main()
{
CAutomobile a[] = {
CAutomobile(),
CAutomobile("Wolkswagen",1970,80.5),
CAutomobile("Fiat",1979,21.9),
CAutomobile("Opel",1978,13.7)
};
for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++) {
cout << "Name" << ' ' << a[i].getName() << endl;
cout << "Year" << ' ' << a[i].getYear() << endl;
cout << "Litres" << ' ' << a[i].getLitres() << endl;
}
int range = 2016 - 1990 + 1;
for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++) {
a[i].setLitres(rand() % 100 + 1);
a[i].setYear(rand() % range + 1996);
}
//сортираме масива по литри и извеждаме
//най малкия (първия) му елемент
for (int i = 0; i < sizeof(a-1); i++) {
for (int j = 0; j < sizeof(a-1); j++) {
if (a[j].getLitres() > a[j + 1].getLitres()) {
swap(a[j], a[j + 1]);
}
}
}
cout << a[0] << endl;
CAutomobile k = a[0] + a[3];
cout << k.getLitres() << endl;
}
CAutomobile::operator = is completely wrong. It takes a non-const reference and assignes its field to a new object. Instead it should take a const reference and modify current object.
CAutomobile & operator =(CAutomobile const & other)
{
assert(this != ::std::addressof(other)); // check for self-assignment
SetName(other.getName());
SetYear(other.getYear());
SetLitres(other.getLitres());
return *this;
}
This will bring up another problem: getters are not const-qualified, so they should be fixes as well:
string const & getName(void) const {
return name;
}
int const & getYear(void) const {
return year;
}
I am writing an assignment that requires me to implement my own (basic) vector class. One unusual requirement, is that we must provide a function which gives the sum of all elements in the vector. This function should cache the sum, so subsequent calls can be answered in constant time if the vector has not changed.
The problem I am having is trying to figure out when it has changed.
#include <iostream>
class MyVector {
int* v;
int size;
int totalSum;
bool upToDate;
public:
MyVector(int size) : size{size}, totalSum{0}, upToDate{false} {
v = new int[size];
for(int i = 0; i < size; i++) {
v[i] = 0;
}
}
// Set - should only be called as an lvalue
int& operator[](unsigned int i) {
upToDate = false;
std::cerr << "Set\n";
return v[i];
}
// Get - should only be called as an rvalue
int operator[](unsigned int i) const {
std::cerr << "Get\n";
return v[i];
}
// Get sum of array -- result is cached for performance
int sum() {
if(!upToDate) {
upToDate = true;
totalSum = 0;
for(int i = 0; i < size; i++) {
totalSum += v[i];
}
}
return totalSum;
}
};
int main() {
MyVector mv(3);
mv[0] = 1;
mv[1] = 2;
mv[2] = 3;
std::cout << "Sum " << mv.sum() << "\n";
int first = mv[0];
std::cout << "First element is " << first << "\n";
std::cout << "Sum " << mv.sum() << "\n";
}
I've provided two overloaded versions of the [] operator -- one for getting and one for setting. Whenever the setting version of the operator is invoked, I assume that the vector is being changed.
# Output
Set
Set
Set
Sum 6
Set
First element is 1
Sum 6
However, it seems the setting version of the operator is always being called, even when it is being used as an rvalue.
How do I overload the [] operator correctly to distinguish between its use for getting and setting?
Instead of returning a reference to the stored int directly, you can return a thin proxy wrapper around that reference, which can watch for changes. In the majority of cases, the compiler should inline it and optimize it away (you can try to benchmark it and compare).
The wrapper class:
class Item {
int &value;
MyVector &myVector;
public:
Item(int &value, MyVector &myVector) : value(value), myVector(myVector) {}
Item& operator=(int newvalue) {
std::cerr << "Set\n";
value = newvalue;
myVector.upToDate = false;
return *this;
}
// TODO: Reimplement also operators like +=, -=, etc
// You can use boost helpers for that.
operator int() const {
std::cerr << "Get\n";
return value;
}
};
Changes to MyVector:
class MyVector {
// ...
Item operator[](unsigned int i) {
return Item(v[i], *this);
}
const int operator[](unsigned int i) const {
std::cerr << "Const Get\n";
return v[i];
}
// ...
}
It can be used exactly the same way:
int main() {
MyVector mv(3);
mv[0] = 1;
mv[1] = 2;
mv[2] = 3;
std::cout << "Sum " << mv.sum() << "\n";
int first = mv[0];
std::cout << "First element is " << first << "\n";
std::cout << "Sum " << mv.sum() << "\n";
}
I have a member function that prints a snapshot of a boost::fibonacci_heap
virtual void printSnapshot(std::ostream& ss) {
Heap heap(this->heap);
double prev_price = DBL_MAX;
while(heap.size() > 0) {
const Order& order = heap.top();
if(order.price != prev_price) {
if(prev_price != DBL_MAX) ss << std::endl;
ss << order.price << " | ";
}
ss << order.quantity << " ";
prev_price = order.price;
heap.pop();
}
ss << std::endl;
}
I call this member function in another member function, which does
while(std::getline(stream, line)) {
... // do something on this->heap.
this->printSnapshot(std::cout);
}
Since the heap is created through a copy constructor at the beginning of "printSnapshot", then "printSnapshot" should change this->heap. However, this program leads to segment fault, while the following does not:
while(std::getline(stream, line)) {
... // do something on this->heap.
// this->printSnapshot(std::cout);
}
Now, if we add a const keyword to the definition of printSnapshot, i.e.
virtual void printSnapshot(std::ostream& ss) const {
Heap heap(this->heap);
double prev_price = DBL_MAX;
while(heap.size() > 0) {
const Order& order = heap.top();
if(order.price != prev_price) {
if(prev_price != DBL_MAX) ss << std::endl;
ss << order.price << " | ";
}
ss << order.quantity << " ";
prev_price = order.price;
heap.pop();
}
ss << std::endl;
}
The segment fault disappears. How could this be explained?
The constructor of fibonacci_heap that takes a lvalue reference (non-const) apparently doesn't do the right things.
It's not documented what it should do: http://www.boost.org/doc/libs/1_55_0/doc/html/boost/heap/fibonacci_heap.html#idp21129704-bb
I assume this might be a reportable bug. I'll look into this a bit.
UPDATE Surprisingly the behaviour of this constructor is apparently equivalent to move-construction:
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
/// \copydoc boost::heap::priority_queue::priority_queue(priority_queue &&)
fibonacci_heap(fibonacci_heap && rhs):
super_t(std::move(rhs)), top_element(rhs.top_element)
{
roots.splice(roots.begin(), rhs.roots);
rhs.top_element = NULL;
}
fibonacci_heap(fibonacci_heap & rhs):
super_t(rhs), top_element(rhs.top_element)
{
roots.splice(roots.begin(), rhs.roots);
rhs.top_element = NULL;
}
The latter has the weird side-effect of simply removing all roots from the original (intrusive) list. This looks like a clear-cut bug.
Simply removing this constructor makes the code work.
The essential workaround is to avoid the lvalue-ref constructor:
Heap cloned(static_cast<Heap const&>(this->heap));
Meanwhile here's a self-contained reproducer:
#include <boost/heap/fibonacci_heap.hpp>
#include <iostream>
#include <random>
namespace {
#undef DBL_MAX
static double DBL_MAX = std::numeric_limits<double>::max();
std::mt19937 rng;
//std::uniform_real_distribution<double> dist(100, 4000);
std::discrete_distribution<int> dist({1,1,1,1,1,1});
static auto price_gen = [&] {
static double values[] = {52.40, 12.30, 87.10, 388., 0.10, 23.40};
return values[dist(rng)];
};
}
struct Order {
double price = price_gen();
unsigned quantity = rand() % 4 + 1;
double subtotal() const { return price * quantity; }
bool operator<(Order const& other) const { return subtotal() < other.subtotal(); }
};
using Heap = boost::heap::fibonacci_heap<Order>;
struct Y {
virtual void printSnapshot(std::ostream &ss) {
//Heap cloned(static_cast<Heap const&>(this->heap));
Heap cloned(this->heap);
double prev_price = DBL_MAX;
while (cloned.size() > 0) {
const Order &order = cloned.top();
if (order.price != prev_price) {
if (prev_price != DBL_MAX)
ss << std::endl;
ss << order.price << " | ";
}
ss << order.quantity << " ";
prev_price = order.price;
cloned.pop();
}
ss << std::endl;
}
void generateOrders() {
for (int i=0; i<3; ++i) {
heap.push({});
}
}
Heap heap;
};
int main() {
Y y;
for(int i=0; i<10; ++i) {
y.generateOrders();
y.printSnapshot(std::cout);
}
}
After really hard search for answers...
I tried fo(u)r hours to get and set values to an array with Overloading the subscript operator “[ ]” but can't figure out why it won't work.
What I'm tring to do here is to set someType value to an array member (On Main "darr1[i] = i*10.0" for example) with overloading the [] and with overloading the = and to get someType value from an array member (On Main "<< darr1[i] << endl" for example) but can't figure out why just the overloading of: "Type & operator [] (int index)" is invoking.
My program doesn't get to the '=' overloading or to the second '[]' overloading at all..
here is my program (sorry for the long one):
#include <iostream>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
class AO1Array
{
private:
int _size;
protected:
int top;
int *B;
int *C;
AO1Array(int n);
~AO1Array();
bool isRealValue(int index)
{
if ((0 <= B[index] && B[index] < top) && (index == C[B[index]]))
return true;
return false;
};
};
AO1Array::AO1Array(int n)
{
_size = n;
top = 0;
B = new int[n];
C = new int[n];
}
AO1Array::~AO1Array()
{
delete[] B;
B = NULL;
delete[] C;
C = NULL;
}
template<class Type>
class GenericO1Array : AO1Array
{
public:
GenericO1Array(int size, Type initVal) : AO1Array(size)
{
_initVal = initVal;
Len = size;
A = new Type[size];
}
~GenericO1Array()
{
delete[] A;
A = NULL;
}
int Length() { return Len; }
Type & operator [](int index) const
{
if (AO1Array::isRealValue(index))
return A[index];
return _initVal;
}
Type & operator [] (int index)
{
if (AO1Array::isRealValue(index))
realValue = true;
else
realValue = false;
return A[index];
}
Type operator =(Type value)
{
if (realValue)
A[lastIndex] = _initVal;
else
{
AO1Array::C[top] = lastIndex;
AO1Array::B[lastIndex] = AO1Array::top++;
A[index] = value;
}
return *this;
}
private:
int Len;
int lastIndex;
bool realValue;
Type _initVal;
Type *A;
};
int main()
{
int n = 20;
GenericO1Array<double> darr1(n, 1.1);
GenericO1Array<long> iarr1(n, 2);
int i;
cout << "\nLength.darr1 = " << darr1.Length() << endl;
cout << "\nLength.iarr1 = " << iarr1.Length() << endl;
for (i = 0; i < n; i += 2)
{
darr1[i] = i*10.0;
iarr1[i] = i * 100;
} // for
cout << "\ndarr1 = " << endl;
for (i = 0; i < n; i++)
cout << "darr1[" << i << "] = " << darr1[i] << endl;
cout << "\niarr1 = " << endl;
for (i = 0; i < n; i++)
cout << "iarr1[" << i << "] = " << iarr1[i] << endl;
} // main
My program doesn't get to the '=' overloading
You are overloading the = assignment operator of Generic01Array itself, but nothing in your code is actually assigning values to your darr1 or iarr1 variables directly (there are no darr1 = ... or iarr = ... statements). That is why your = operator is not being invoked.
If you want something to happen when the user assigns a value to an element of your array, you need to create a proxy class and overload its = assignment operator, then have your [] operator return an instance of that proxy:
template<class Type>
class GenericO1Array : AO1Array
{
public:
class Proxy;
friend Proxy;
class Proxy
{
private:
Generic01Array& _arr;
int _index;
public:
Proxy(Generic01Array &arr, int index) : _arr(arr), _index(index) {}
operator Type() const
{
if (_arr.isRealValue(index))
_arr.realValue = true;
else
_arr.realValue = false;
return _arr.A[_index];
}
Proxy& operator=(const Type &value)
{
if (_arr.realValue)
_arr.A[_arr.lastindex] = _arr._initVal;
else
{
_arr.C[_arr.top] = _arr.lastIndex;
_arr.B[_arr.lastIndex] = _arr.top++;
_arr.A[_index] = value;
}
return *this;
}
};
...
Proxy operator [] (int index)
{
return Proxy(*this, index);
}
...
};
or to the second '[]' overloading at all..
You have two overloads of the [] operator, one that is const and the other is not. The const version of [] is breaking the const-ness of the operator by returning a non-const reference to the array's internal data. It should be returning a non-reference const value instead:
const Type operator [](int index) const
The non-const version of the [] operator can return a reference:
Type& operator [](int index)
You are not calling the [] operator on any const instances of your Generic01Array class, so only the non-const version of your [] operator should be getting invoked.
Good afternoon, I am finding that std:multimap::equal_range returns incorrect results sometimes. Is this possible? If so, is there a workaround or some error in my code or hash function for pointers. Thank you.
Here is an excerpt of my code:
typedef std::multimap<char *,Range>::const_iterator I;
std::pair<I,I> b = mmultimap.equal_range(TmpPrevMapPtr);
for (I i=b.first; i != b.second; ++i){
ranges_type.erase(i->second);
}
erasecount = mmultimap.erase(TmpPrevMapPtr);
where mmultimap has a hashed pointer key and a Range value. The class Range looks like this:
class Range {
public:
explicit Range(int item){// [item,item]
mLow = item;
mHigh = item;
mPtr = 0;
mMapPtr = 0;
mStamp = 0;
}
Range(int low, int high, char* ptr = 0,char* mapptr, int stamp){
mLow = low;
mHigh = high;
mPtr = ptr;
mMapPtr = mapptr;
mStamp = stamp;
}
int low() const { return mLow; }
int high() const { return mHigh; }
char* getPtr() const { return mPtr; }
char* getMapPtr() const { return mMapPtr; }
int getStamp() const { return mStamp; }
private:
int mLow;
int mHigh;
char* mPtr;
char* mMapPtr;
int mStamp;
}; // class Range
You are comparing char* pointers for equality, when you want to compare C strings. You need to supply a comparison functor to multimap or (better yet) use std::string. Consider the following program and note how A1 != A2, but strcmp(A1, A2)==0.
#include <map>
#include <string>
#include <cstring>
#include <iostream>
struct compare {
bool operator()(char *left, char *right) const {
return std::strcmp(left,right) < 0;
}
};
int main() {
char A1[] = "A";
char A2[] = "A";
std::multimap<char*, int> bad;
bad.insert(std::pair<char*,int>(A1, 1));
bad.insert(std::pair<char*,int>(A2, 1));
std::cout << bad.count("A") << ", " << bad.count(A1) << "\n";
std::multimap<char*, int, compare> good;
good.insert(std::pair<char*,int>(A1, 1));
good.insert(std::pair<char*,int>(A2, 1));
std::cout << good.count("A") << ", " << good.count(A1) << "\n";
std::multimap<std::string, int> better;
better.insert(std::pair<std::string,int>(A1, 1));
better.insert(std::pair<std::string,int>(A2, 1));
std::cout << better.count("A") << ", " << better.count(A1) << "\n";
}
The way you are using the iterators is wrong. When using the erase method, the iterator became invalid. It must be reassigned with the erase method returned value.
In other words:
for (I i=b.first; i != b.second; ++i){
ranges_type.erase(i->second);
}
should be
I i = b.first;
while (i != b.second){
i = ranges_type.erase(i->second);
}