What does String do that I'm not doing? c++11 - c++11

I am still new to c++, so bear with me.
I was trying to learn more about how std::move works and I saw an example where they used std::move to move the string to a different function and then showed using std::cout that no string remained. I thought cool, let's see if I can make my own class and do the same:
#include <iostream>
#include <string>
class integer
{
private:
int *m_i;
public:
integer(int i=0) : m_i(new int{i})
{
std::cout << "Calling Constructor\n";
}
~integer()
{
if(m_i != nullptr) {
std::cout << "Deleting integer\n";
delete m_i;
m_i = nullptr;
}
}
integer(integer&& i) : m_i(nullptr) // move constructor
{
std::cout << "Move Constructor\n";
m_i = i.m_i;
i.m_i = nullptr;
}
integer(const integer& i) : m_i(new int) { // copy constructor
std::cout << "Copy Constructor\n";
*m_i = *(i.m_i);
}
//*
integer& operator=(integer&& i) { // move assignment
std::cout << "Move Assignment\n";
if(&i != this) {
delete m_i;
m_i = i.m_i;
i.m_i = nullptr;
}
return *this;
}
integer& operator=(const integer &i) { // copy assignment
std::cout << "Copy Assignment\n";
if(&i != this) {
m_i = new int;
*m_i = *(i.m_i);
}
return *this;
}
int& operator*() const { return *m_i; }
int* operator->() const { return m_i; }
bool empty() const noexcept {
if(m_i == nullptr) return true;
return false;
}
friend std::ostream& operator<<(std::ostream &out, const integer i) {
if(i.empty()) {
std::cout << "During overload, i is empty\n";
return out;
}
out << *(i.m_i);
return out;
}
};
void g(integer i) { std::cout << "G-wiz - "; std::cout << "The g value is " << i << '\n'; }
void g(std::string s) { std::cout << "The g value is " << s << '\n'; }
int main()
{
std::string s("Hello");
std::cout << "Now for string\n";
g(std::move(s));
if(s.empty()) std::cout << "s is empty\n";
g(s);
std::cout << "\nNow for integer\n";
integer i = 77;
if(!i.empty()) std::cout << "i is " << i << '\n';
else std::cout << "i is empty\n";
g(i);
std::cout << "Move it\n";
g(std::move(i)); // rvalue ref called
if(!i.empty()) std::cout << "i is " << i << '\n';
else std::cout << "i is empty\n";
g(i);
return 0;
}
And this is my output:
Now for string
The g value is Hello
s is empty
The g value is
Now for integer
Calling Constructor
Copy Constructor
i is 77
Deleting integer
Copy Constructor
G-wiz - Copy Constructor
The g value is 77
Deleting integer
Deleting integer
Move it
Move Constructor
G-wiz - Copy Constructor
The g value is 77
Deleting integer
Deleting integer
i is empty
Copy Constructor
Process returned 255 (0xFF) execution time : 7.633 s
Press any key to continue.
As you can see, it crashes when it enters g the second time, never even getting to the operator<<() function. How is it that the empty std::string s can be passed to g where my empty integer i crashes the program?
Edit: Fixed new int vs. new int[] error. Thanks n.m.

Your "empty integer" crashes the program because it contains a null pointer. You are trying to dereference it when you use it at the right hand side of the assignment.
An empty string is a normal usable string. There are no unchecked null pointer dereferences in the std::string code.
You have to ensure that the empty state of your object is a usable one. Start with defining a default constructor. Does it make sense for your class? If not, then move semantic probably doesn't either. If yes, a moved-from object in the move constructor should probably end up in the same state as a default-constructed object. A move assignment can act as a swap operation, so there the right-hand-side may end up either empty or not.
If you don't want to define a usable empty state for your class, and still want move semantics, you simply cannot use an object after it has been moved from. You still need to make sure that an empty object is destructible.

Related

c++11 how to check template parameter pack has N args before calling function with N args

Following on from this extracting a template parameter pack with different types into a vector of doubles produces warnings and cigien's answer.
I have the following code:
enum class p_type {p1, p2, p3};
class testerx
{
public:
void process1(double a)
{
std::cout << "1" << a << std::endl;
};
void process2(double a, double b)
{
std::cout << "2" << a << " " << b << std::endl;
};
void process3(double a, double b, double c)
{
std::cout << "3" << a << " " << b << " " << c << std::endl;
};
};
// The template type
template<typename TESTER, typename... ARGS>
class tester_templatex
{
public:
explicit tester_templatex(p_type type) : m_type(type) {};
void process(ARGS... args)
{
// Create a vector to put the args into. use double since that can hold all of the types
// that I am using
size_t param_count = sizeof...(args);
std::cout << "PARAM COUNT X " << param_count << std::endl;
std::vector<double> args_vect = {static_cast<double>(args)...};
for (auto arg : args_vect)
{
std::cout << "arg: " << arg << std::endl;
}
// Now call the tester
std::cout << "running tester: ";
switch (m_type)
{
case p_type::p1:
if constexpr (sizeof...(args) == 1)
m_tester.process1(args...);
break;
case p_type::p2:
if constexpr (sizeof...(args) == 2)
m_tester.process2(args...);
break;
case p_type::p3:
if constexpr (sizeof...(args) == 3)
m_tester.process3(args...);
break;
}
std::cout << std::endl;
};
p_type m_type;
TESTER m_tester;
};
main:
int main() {
tester_templatex<testerx, int> templatex1(p_type::p1);
tester_templatex<testerx, int, double> templatex2(p_type::p2);
tester_templatex<testerx, int, double, int> templatex3(p_type::p3);
templatex1.process(4);
templatex2.process(4, 5.123);
templatex3.process(4, 5.123, 6);
return 0;
}
Here I have test class with 3 different functions. I have a template class which picks the function to call based on the p_type (bad name - dont ask!).
This works for c++17 compiled code. But I only have c++11 where I need to run this code. c++11 does not support if constexpr:
case p_type::p3:
if constexpr (sizeof...(args) == 3)
m_tester.process3(args...);
break;
Without the if constexpr I get errors that the m_tester.process1/2/3 functions that don't match the parameter pack because they don't have the right number of parameters.
How can I fix this for c++11? - is it possible with a similar method?
Is there another way to extract N arguments from a parameter pack in c++11? - or some sort of type traits check?
For each of your functions have an overload that does nothing:
template<typename... ARGS>
void process3(ARGS&...) { }
and then just call the function without testing for the size of the pack:
case p_type::p3:
m_tester.process3(args...);
break;
This should pick the non-templated function when there are suitably many arguments, and the function template in other cases.

why map emplace calling rvalue constructor twice

class twoMem {
int _a;
int _b;
public:
twoMem() {
std::cout << "default constructor" << std::endl;
}
twoMem(int a, int b) :_a(a), _b(b) {
std::cout << "constructor called" << std::endl;
}
twoMem(const twoMem& other) {
std::cout << "copy constructor called" << std::endl;
_a = other._a;
_b = other._b;
}
twoMem(const twoMem&& other) {
std::cout << "rvalue copy constructor called" << std::endl;
_a = other._a;
_b = other._b;
}
~twoMem() {
std::cout << "destructor called" << std::endl;
}
};
int main()
{
std::map<std::string, twoMem> myMap{};
myMap.emplace(std::make_pair("foo", twoMem{ 1, 2 }));
return 0;
}
output:
constructor called
rvalue copy constructor called
rvalue copy constructor called
destructor called
destructor called
destructor called
First, make_pair moves from twoMem argument into pair<const char*, twoMem> it returns. Second, emplace() moves from that into actual node.
Make it
myMap.emplace("foo", twoMem{ 1, 2 });
then the move constructor is only called once. That's kind of the point of map::emplace.
You can get to zero copy or move constructors this way:
myMap.emplace(std::piecewise_construct, std::make_tuple("foo"), std::make_tuple(1, 2));
Though arguably this cure may be worse than the disease, as now you are constructing and copying tuples around, which is likely at least as expensive as copying twoMem.

Which one to choose between pointer way and non pointer way?

#include <iostream>
class A{
public:
A(){std::cout << "basic constructor called \n";};
A(const A& other) {
val = other.x
std::cout << "copy constructor is called \n";
}
A& operator=(const A& other){
val = other.x
std::cout << "\n\nassignment operator " << other.val << "\n\n";
}
~A(){
std::cout << "destructor of value " << val <<" called !!\n";
}
A(int x){
val = x;
std::cout << " A("<<x<<") constructor called \n";
}
int get_val(){
return val;
}
private:
int val;
};
int main(){
// non pointer way
A a;
a = A(1);
std::cout << a.get_val() << std::endl;
a = A(2);
std::cout << a.get_val() << std::endl;
// pointer way
A* ap;
ap = new A(13);
std::cout << ap->get_val() << std::endl;
delete ap;
ap = new A(232);
std::cout << ap->get_val() << std::endl;
delete ap;
return 0;
}
I initially create an object out of default constructor and then assign tmp r-value objects A(x) to a. This ends up calling assignment operator. So in this approach there are 3 steps involved
(non-pointer way)
1) constructor
2) assignment operator
3) destructor
Where as when I use pointer it only requires two step
(pointer way)
1) constructor
2) destructor
My question is should I use non-pointer way to create new classes or should I use pointer way. Because I have been said that I should avoid pointers (I know I could also use shared_ptr here).
Rule of thumb: Prefer to create objects on the stack. There is less work for memory management when you create objects on the stack. It is also more efficient.
When do you have to create objects on the heap?
Here are some situations that need it:
You need to create an array of objects where the size of the array is known only at run time.
You need an object to live beyond the function in which it was constructed.
You need to store and/or pass around a pointer to a base class type but the pointer points to a derived class object. In this case, the derived class object, most likely, will need to be created using heap memory.

find chars/string in string from vector c++

I have a vector of strings, and I want to count all 'Ace' in the vector. Right now I can only find one...
int main()
{
std::vector<string> vec;
vec.push_back("Ace of Spades");
vec.push_back("Ace");
string value = "Ace";
int cnt = 0;
auto iter = find_if(begin(vec), end(vec), [&](const string &str)
{
return str.find(value) != str.npos;
});
if(iter == end(vec))
cout << "no found" << endl;
else
{
cout << *iter << endl;
cnt++;
cout << cnt++ << endl;
}
}
You could use std::count_if:
auto cnt = count_if(begin(vec),
end(vec),
[&](const string& str) {
return str.find(value) != std::string::npos;
});
Note that this only counts the number of strings containing "Ace", not the total number of occurrences of "Ace" in the vector's elements.
If you just want to count the number of matching elements, you could use std::count_if.
If you also need to do something with them, it would probably be best to forget about the standard library algorithms and use a ranged for like so:
int count = 0;
for (const auto& element : vec) {
if (element.find(value) != std::string::npos) {
std::cout << element << std::endl;
++count;
}
}
std::cout << count << std::endl;

Trouble with Nested Lambdas

I am probably making some elementary mistake here but given:
std::array<int, 3> arr = { 1, 2, 3 };
std::vector<int> vecint;
vecint.push_back(1);
vecint.push_back(2);
This is one obvious way to compare the elements in arr with the ones in vecint.
std::for_each(vecint.begin(), vecint.end(), [&arr](int vecvalue) {
for (auto arritr = arr.begin(); arritr != arr.end(); ++arritr) {
if (vecvalue == *arritr) {
std::cout << "found!!! " << vecvalue << "\n";
}
}
});
However, should I be able to do it like this too?
std::for_each(vecint.begin(), vecint.end(), [&arr](int vecvalue) {
if (std::find(arr.begin(), arr.end(), [=](int arrval) { return vecvalue == arrval; }) != arr.end()) {
std::cout << "found!!! " << vecvalue << "\n";
}
});
The latter fails to compile in VC11 with the following error:
1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\xutility(3186): error C2678: binary '==' : no operator found which takes a left-hand operand of type 'int' (or there is no acceptable conversion)
What am I missing?
cppreference on std::find and std::find_if
std::find takes a value to compare with as the third parameter, whereas std::find_if takes a UnaryPredicate (a function object taking one parameter). You probably just had a typo / wanted to use std::find_if.
Using std::find_if works for me. Live example.
#include <array>
#include <vector>
#include <iostream>
#include <algorithm>
int main()
{
std::array<int, 3> arr = {{ 1, 2, 3 }};
std::vector<int> vecint;
vecint.push_back(1);
vecint.push_back(2);
std::for_each
(
vecint.begin(), vecint.end(),
[&arr](int vecvalue)
{
if (std::find_if(arr.begin(), arr.end(),
[=](int arrval) { return vecvalue == arrval; })
!= arr.end())
{
std::cout << "found!!! " << vecvalue << "\n";
}
}
);
}
A simpler version is of course to use std::find (correctly):
std::for_each
(
vecint.begin(), vecint.end(),
[&arr](int vecvalue)
{
if (std::find(arr.begin(), arr.end(), vecvalue) != arr.end())
{
std::cout << "found!!! " << vecvalue << "\n";
}
}
);
Then, there's of course the range-based-for-loop variant, if your compiler supports it:
for(auto const& ve : vecint)
{
for(auto const& ae : arr)
{
if(ve == ae)
{
std::cout << "found!!! " << ve << "\n";
}
}
}
If your ranges are sorted, there are faster algorithms to get the intersection. Either you write your own loop to invoke an action for each element in the intersection, or you let the Standard Library copy the intersection into a new container:
#include <iterator> // additionally
std::vector<int> result;
std::set_intersection(arr.begin(), arr.end(), vecint.begin(), vecint.end(),
std::back_inserter(result));
for(auto const& e : result)
{
std::cout << e << std::endl;
}
What happens under the hood - why you get that error:
std::find is defined as (from cppreference):
template< class InputIt, class T >
InputIt find( InputIt first, InputIt last, const T& value );
That is, the type of value and the type of the iterators are independent. However, in the implementation of std::find, there has to be a comparison like:
if(*first == value) { return first; }
And at this point, you're comparing an int (type of the expression *first) with a lambda (type of value) more precisely: with a closure type. This is ill-formed (luckily), as there's no conversion from a lambda to an int, and there's no comparison operator declared that's applicable here.

Resources