Equality of container object identity instead of element-wise - c++

#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> fst, snd;
vector<int> trd = fst;
cout << boolalpha << (fst == snd) << endl;
}
The operator== is overloaded for vectors fst, snd to check element-wise equality.
Instead, how to check that fst references to the same object as trd? (In this case the keyword is used in Python.)
#EDIT
As all the answers and comments said, object, object pointer and object reference are distinguished concepts in C++:
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
int main() {
// object pointer, heap allocated
shared_ptr<vector<int>> fst(new vector<int>);
auto snd = fst;
fst->push_back(10);
cout << boolalpha << (fst->size() == snd->size()) << endl;
snd->push_back(20);
cout << (fst->size() == snd->size()) << endl;
fst = make_shared<vector<int>>();
cout << (fst == snd) << endl;
// object reference, aka alias
vector<int> trd{3};
auto &foth = trd;
trd[0] = 30;
cout << (trd[0] == foth[0]) << endl;
foth[0] = 40;
cout << (trd[0] == foth[0]) << endl;
trd = {};
cout << (trd == foth) << endl;
// object copy, stack allocated
vector<int> fith{5};
auto sith = fith;
fith[0] = 50;
cout << (fith[0] == sith[0]) << endl;
sith[0] = 60;
cout << (fith[0] == sith[0]) << endl;
fith = {};
cout << (fith == sith) << endl;
}

You are using C++, not Python. In C++, a variable of object type is the object; it doesn't "reference" anything. fst and snd are separate variables and therefore are separate objects. The only valid comparison is to ask the value of their objects if they are equivalent.
Variables of reference type don't provide the operation you're looking for either. A reference variable is intended to act (as much as practical) exactly like the object it references. References are commonly said to be a different name for the same object. So asking the question if two reference variables reference the same object is considered irrelevant in C++.
If you need to make this distinction between "referencing the same object" and "objects with the same value" (and you rarely do), then you need to use the C++ mechanism that provides that distinction: pointers. There, you can check for pointer equivalence (and thus "references the same object") or dereference the pointers and check for object equivalence.

In order to experiment around the question, here is an example
that tries to mimic the behavior of Python.
The values are only accessible through references (smart-pointers
here) so you have to explicitly say if you want to compare the
references (addresses) or the values.
/**
g++ -std=c++17 -o prog_cpp prog_cpp.cpp \
-pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion \
-g -O0 -UNDEBUG -fsanitize=address,undefined
**/
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
using vec_t = std::vector<std::shared_ptr<int>>;
int
main()
{
const vec_t v1={std::make_shared<int>(1),
std::make_shared<int>(2),
std::make_shared<int>(3)};
const vec_t v2={std::make_shared<int>(1), // the three same values
std::make_shared<int>(2), // but it's just a
std::make_shared<int>(3)}; // coincidence...
const vec_t v3=v1; // references to the same 3 data are shared between both vectors
std::cout << std::boolalpha;
std::cout << "compare references (addresses):\n";
std::cout << "v1==v2 --> " << (v1==v2) << '\n'; // false
std::cout << "v1==v3 --> " << (v1==v3) << '\n'; // true
const auto same_values=
[&](const auto &lhs, const auto &rhs)
{
return std::equal(cbegin(lhs), cend(lhs), cbegin(rhs), cend(rhs),
[&](const auto &l, const auto &r)
{
return *l==*r; // dereference before comparing the values
});
};
std::cout << "compare values:\n";
std::cout << "same_values(v1, v2) --> " << same_values(v1, v2) << '\n'; // true
std::cout << "same_values(v1, v3) --> " << same_values(v1, v3) << '\n'; // true
return 0;
}

Related

What am I iterating in this find_if function?

Here is my code:
bool isNotValid (char a) {
if (isalpha(a) || a == '_')
{
cout << "\n- isalpha";
return 0;
}
else
{
cout << "\n- notalpha";
return 1;
}
}
bool test123(const string& test)
{
return find_if(test.begin(), test.end(), isNotValid) != test.end();
}
int main()
{
string test;
cout << "Test input: ";
cin >> test;
if (!test123(test))
cout << "\n- Valid\n";
else
cout << "\n- Not Valid\n";
return 0;
}
This is part of my code to check the validity of username in my program. I don't really understand what exactly I am iterating through when I insert the string into my function as address of the string. CPP reference states that find_if iterates from first to last position of a sequence.
Poked through the code with cout at different location, still didn't quite catch what is going on.
You are iterating your string. You did not pass the address of the string. The function takes the string as a reference to const, meaning it passes the actual string (no copy is made) and the function is not allowed to modify the string. You are iterating character by character in your string and calling your function isNotValid() on each character.
Notes:
Instead of returning 1 or 0 from isNotValid(), return true or false.
Consider flipping your logic and renaming the function to isValid() instead. You would also have to change test123() to use std::find_if_not(). Finally, you would check if the returned iterator is end() and not if it's not.
But, if you do change isNotValid() to isValid(), you'd be better off switching from std::find_if() entirely to to std::all_of(). It makes more sense, is more readable, and returns a bool directly (No need to compare against end()).
But if you want to keep your function isNotValid(), the comment that suggests using std::any_of() is what I would recommend for the same reasons.
Here's my take on your code:
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
bool isValid(char a) {
return std::isalpha(static_cast<unsigned char>(a)) || a == '_'; // !
}
bool test123(const std::string& test) {
return std::all_of(test.begin(), test.end(), isValid); // !
}
int main() {
std::string testOne{"i_am_valid"};
std::string testTwo{"i_am_invalid_123"};
std::cout << "Testing: " << testOne << " : " << std::boolalpha
<< test123(testOne) << '\n';
std::cout << "Testing: " << testTwo << " : " << std::boolalpha
<< test123(testTwo) << '\n';
}
Output:
❯ ./a.out
Testing: i_am_valid : true
Testing: i_am_invalid_123 : false
I would argue that readability has stayed largely the same, but the mental load has been shifted; the Boolean flips make a bit more sense.
As you progress in your learning, you might not even want to have the function isValid() if it's a one-off thing. C++11 introduced lambdas, or functions as objects. C++20 also introduced ranges, so you don't have to pass a pair of iterators if you intend to iterate the whole container anyway.
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
bool test123(const std::string& test) {
return std::ranges::all_of(test, [](const auto& c) {
return std::isalpha(static_cast<unsigned char>(c)) || c == '_';
}); // !
}
int main() {
std::string testOne{"i_am_valid"};
std::string testTwo{"i_am_invalid_123"};
std::cout << "Testing: " << testOne << " : " << std::boolalpha
<< test123(testOne) << '\n';
std::cout << "Testing: " << testTwo << " : " << std::boolalpha
<< test123(testTwo) << '\n';
}
That's a bit hairy to read if you're not familiar with lambdas, but I find lambdas useful for checks like this where you're just doing it the one time.

Does Boost Variant provides a similar function as std's holds_alternative?

I found this code on cppreference.com. I was wondering if boost provides a similar function for its variant type. I found the boost documentation really awful and can't find anything.
int main()
{
std::variant<int, std::string> v = "abc";
std::cout << std::boolalpha
<< "variant holds int? "
<< std::holds_alternative<int>(v) << '\n'
<< "variant holds string? "
<< std::holds_alternative<std::string>(v) << '\n';
}
Although not exactly the same, you can use the pointer based get function:
boost::variant<int, std::string> v = "abc";
std::cout << std::boolalpha
<< "variant holds int? "
<< (boost::get<int>(&v) != nullptr) << '\n'
<< "variant holds string? "
<< (boost::get<std::string>(&v) != nullptr) << '\n';
You can create a simple wrapper that will work just like the standard one. Use the fact that boost::get has multiple overloads and when passed a pointer, it will also return a (possibly null) pointer.
template <typename T, typename... Ts>
bool holds_alternative(const boost::variant<Ts...>& v) noexcept
{
return boost::get<T>(&v) != nullptr;
}
It will be also picked up by ADL, so it doesn't matter much where you put it.
No but, you can use the type() method:
#include <iostream>
#include <boost/variant.hpp>
int main()
{
boost::variant<int, std::string> v = "abc";
std::cout << std::boolalpha
<< "variant holds int? "
<< (v.type() == typeid(int)) << '\n'
<< "variant holds string? "
<< (v.type() == typeid(std::string)) << '\n';
}
But it will not protect you against having the same type twice (boost::variant<int, int, std::string>) as std::holds_alternative would do.

Rcpp: Is a wrapping class the only way to preserve fundamental types pointed to by Xptr?

I have a fair bit of experience with R, but am only now getting down to the business of learning C++, so I beg forgiveness for any ensuing stupidity....
Given the following test.cpp file:
#include <Rcpp.h>
#include <string>
using namespace Rcpp;
using namespace std;
XPtr< double > getPtr(NumericVector x) {
double i;
i = REAL(x)[0];
XPtr< double > p(&i, false);
XPtr<double> checkP(p);
double checkV = *checkP;
cout << "Values within getPtr scope:" << endl;
cout << "Pointer address " << hex << checkP << endl;
cout << "Pointer value " << checkV << endl;
return p;
}
// [[Rcpp::export]]
void testPtr(NumericVector x){
XPtr<double> p(getPtr(x));
cout << "Values outside of getPtr scope:" << endl;
cout << "Pointer address " << hex << p << endl;
cout << "Pointer value " << *p << endl;
return;
}
The following R snippet demonstrates that the value pointed to by the Xptr "disappears" outside the getPtr function.
> library(Rcpp)
> Rcpp::sourceCpp(file="test.cpp")
>
> test <- c(35,28,16,52)
> testPtr(test)
Values within getPtr scope:
Pointer address 0x7ffd3763d790
Pointer value 35
Values outside of getPtr scope:
Pointer address 0x7ffd3763d790
Pointer value 6.95277e-310
But of course! Since that value is out of scope, this is expected behavior.
Alternatively, if I wrap the value in a class and use new, the object persists and I can retrieve my value outside the scope of the called function:
class Wrap {
public:
Wrap(double x) {
i = x;
}
double i;
};
XPtr< Wrap > getPtrW(NumericVector x) {
double i;
i = REAL(x)[0];
Wrap* w = new Wrap(i);
XPtr< Wrap > p(w, true);
return p;
}
// [[Rcpp::export]]
void testWrappedPtr(NumericVector x){
XPtr<Wrap> wp(getPtrW(x));
Wrap w = *(wp);
cout << "Wrapped value " << w.i << endl;
return;
}
Then this demonstrates that the value persists as desired:
> testWrappedPtr(test)
Wrapped value 35
My questions (at last) are these: (1) Is this (i.e. wrapping in a class) the only way to hang on to values of variables that are fundamental types and not malloc'd or new'd and (2) if not, are any of the alternative ways "better" or "preferred"?
Thanks in advance!

Does this use of std::make_unique lead to non-unique pointers?

Suppose I have the following code in C++:
#include <memory>
#include <iostream>
struct Some {
Some(int _a) : a(_a) {}
int a;
};
int main() {
Some some(5);
std::unique_ptr<Some> p1 = std::make_unique<Some>(some);
std::unique_ptr<Some> p2 = std::make_unique<Some>(some);
std::cout << p1->a << " " << p2->a << std::endl;
return 0;
}
As I understand, unique pointers are used to guarantee that resources are not shared. But in this case both p1 and p2 point to the same instance some.
Please unveil the situation.
They don't point to the same resource, they each point to a different copy of it. You can illustrate it by deleting the copy constructor to see the error:
#include <memory>
#include <iostream>
struct Some {
Some(int _a) : a(_a) {}
Some(Some const&) = delete;
int a;
};
int main() {
Some some(5);
std::unique_ptr<Some> p1 = std::make_unique<Some>(some); //error here
std::unique_ptr<Some> p2 = std::make_unique<Some>(some);
std::cout << p1->a << " " << p2->a << std::endl;
return 0;
}
std::make_unique creates objects, calling constructor with specified arguments.
You passed Some& as parameter, and here copy constructor was invoked, and new object constructed.
So, p1 and p2 are 2 absolutely different pointers, but constructed from same object, using copy constructor
both p1 and p2 point to the same instance some
No, they don't.
#include <memory>
#include <iostream>
struct Some {
Some(int _a) : a(_a) {}
int a;
};
int main() {
Some some(5);
std::unique_ptr<Some> p1 = std::make_unique<Some>(some);
std::unique_ptr<Some> p2 = std::make_unique<Some>(some);
std::cout << p1->a << " " << p2->a << std::endl;
p1->a = 42;
std::cout << p1->a << " " << p2->a << std::endl;
return 0;
}
output:
5 5
42 5
To test whether two pointers point to the same object instance, you should compare the locations they point to, instead of the object member variables:
std::cout << &(*p1) << " " << &(*p2) << std::endl;
Which will show that they indeed do not point to the same instance.
ADDENDUM: As pointed out by Remy Lebeau, since C++11 it is advisable to use the
std::addressof function for this purpose, which obtains the actual address of an object even if the & operator is overloaded:
std::cout << std::addressof(*p1) << " " << std::addressof(*p2) << std::endl;

Moving objects from one unordered_map to another container

My question is that of safety. I've searched cplusplus.com and cppreference.com and they seem to be lacking on iterator safety during std::move. Specifically: is it safe to call std::unordered_map::erase(iterator) with an iterator whose object has been moved? Sample code:
#include <unordered_map>
#include <string>
#include <vector>
#include <iostream>
#include <memory>
class A {
public:
A() : name("default ctored"), value(-1) {}
A(const std::string& name, int value) : name(name), value(value) { }
std::string name;
int value;
};
typedef std::shared_ptr<const A> ConstAPtr;
int main(int argc, char **argv) {
// containers keyed by shared_ptr are keyed by the raw pointer address
std::unordered_map<ConstAPtr, int> valued_objects;
for ( int i = 0; i < 10; ++i ) {
// creates 5 objects named "name 0", and 5 named "name 1"
std::string name("name ");
name += std::to_string(i % 2);
valued_objects[std::make_shared<A>(std::move(name), i)] = i * 5;
}
// Later somewhere else we need to transform the map to be keyed differently
// while retaining the values for each object
typedef std::pair<ConstAPtr, int> ObjValue;
std::unordered_map<std::string, std::vector<ObjValue> > named_objects;
std::cout << "moving..." << std::endl;
// No increment since we're using .erase() and don't want to skip objects.
for ( auto it = valued_objects.begin(); it != valued_objects.end(); ) {
std::cout << it->first->name << "\t" << it->first.value << "\t" << it->second << std::endl;
// Get named_vec.
std::vector<ObjValue>& v = named_objects[it->first->name];
// move object :: IS THIS SAFE??
v.push_back(std::move(*it));
// And then... is this also safe???
it = valued_objects.erase(it);
}
std::cout << "checking... " << named_objects.size() << std::endl;
for ( auto it = named_objects.begin(); it != named_objects.end(); ++it ) {
std::cout << it->first << " (" << it->second.size() << ")" << std::endl;
for ( auto pair : it->second ) {
std::cout << "\t" << pair.first->name << "\t" << pair.first->value << "\t" << pair.second << std::endl;
}
}
std::cout << "double check... " << valued_objects.size() << std::endl;
for ( auto it : valued_objects ) {
std::cout << it.first->name << " (" << it.second << ")" << std::endl;
}
return 0;
}
The reason I ask is that it strikes me that moving the pair from the unordered_map's iterator may (?) therefore *re*move the iterator's stored key value and therefore invalidate its hash; therefore any operations on it afterward could result in undefined behavior. Unless that's not so?
I do think it's worth noting that the above appears to successfully work as intended in GCC 4.8.2 so I'm looking to see if I missed documentation supporting or explicitly not supporting the behavior.
// move object :: IS THIS SAFE??
v.push_back(std::move(*it));
Yes, it is safe, because this doesn't actually modify the key. It cannot, because the key is const. The type of *it is std::pair<const ConstAPtr, int>. When it is moved, the first member (the const ConstAPtr) is not actually moved. It is converted to an r-value by std::move, and becomes const ConstAPtr&&. But that doesn't match the move constructor, which expects a non-const ConstAPtr&&. So the copy constructor is called instead.