I'm writing some codes in which there are 2 vectors containing 4 smart pointers respectively. I accidentally apply an iterator generated in the first vector to the erase method in the second vector. Then the program crashes. I learn that the copy construction and the move construction get involved the erase method. In light of the debugger, I figure out 1) a nullptr and 2 smart pointers stay in 1st vector. 2) 4 smart pointers reside in 2nd vector. 3) the program starts to crash after several successful run. My questions are as follows,
how is the nullptr appended to 1st vector?
Why is it permissible to apply the iterator to 2nd vector?
Why does the program not crash from the outset?
BTW, my platform is Xcode 8.1. Thanks in advance
#include <memory>
#include <vector>
#include <iostream>
#include <string>
using namespace std;
class A{
public:
A(string name_) : name(name_) {cout << name << " construction\n";}
const string& get_name() const {return name;}
~A() {cout <<get_name() << " destruction\n";}
A (const A& rhs) : name(rhs.name){cout << "A copy constructor\n";}
A(A&& rhs) : name(""){
cout <<"A move constructor\n";
swap(rhs);
}
void swap(A& rhs) noexcept {
std::swap(name, rhs.name);
}
private:
string name;
};
void foo();
int main(){
foo();
}
void foo(){
vector<shared_ptr<A>> vect1, vect2;
auto a1 = make_shared<A>("Mike");
auto a2 = make_shared<A>("Alice");
auto a3 = make_shared<A>("Peter");
auto a4 = make_shared<A>("Paul");
vect1.push_back(a1);
vect1.push_back(a2);
vect1.push_back(a3);
vect1.push_back(a4);
vect2.push_back(a4);
vect2.push_back(a1);
vect2.push_back(a2);
vect2.push_back(a3);
auto it = vect1.begin();
vect1.erase(it);
for (auto &c : vect1){
cout << c->get_name() << endl;
}
vect2.erase(it);
for (auto &c : vect2){
cout << c->get_name() << endl;
}
}
In VS2015 it fails on line vect2.erase(it); with the message; Iterator out of bounds which indeed it is.
As you state in the question it doesn't even belong to vect2.
Even if it works on your platform it is undefined behavior. So from then on anything can happen.
You're not working within the c++ standard anymore, you're now dealing with whichever way your platform was implemented (maybe it uses pointers for iterators, maybe it uses offsets; who knows?).
Related
I am learning to use C++ vectors, and I can't quite understand the output of the following program:
#include <iostream>
#include <vector>
using namespace std;
class Custom {
public:
int v;
Custom() = delete;
explicit Custom(int v) : v{v} {};
Custom(const Custom &) : v{4} {
}
friend ostream &operator<<(ostream &os, const Custom &th) {
os << "V is " << th.v << endl;
return os;
}
};
int main(int argc, char *argv[]) {
vector<Custom> c(2, Custom(3));
c[0].v = 5;
for (auto i: c) {
cout << i << endl;
}
}
I expected it to produce the output
V is 5
V is 4
But instead it produces
V is 4
V is 4
Am I missing something obvious? Thanks.
This range based loop is making copies:
for (auto i: c) {
cout << i << endl;
}
And the copy constructor initializes v to 4 (and does not make a copy):
Custom(const Custom &) : v{4} {
}
You can either implement a proper copy constructor or use references in the loop to get the desired output:
for (const auto& i: c) {
cout << i << endl;
}
I would suggest to do both, because this copy constructor is not doing a copy by any means. The compiler generated copy constructor should be fine:
Custom(const Custom &) = default;
PS: The fact that Custom has a deleted default constructor is not really relevant for the posted code. Nowhere in the code a Custom is default constructed. Also there is no iterator in your code. In the range based loop i is a copy/reference of the elements in the vector, it is not an iterator.
When you wrote:
for (auto i: c) //this uses copy constructor to copy initialize each element one by one from the vector
{
}
In the above snippet, each individual element of the vector is used to copy initiaize a temporary object named i while iterating through the vector. And since you have the v{4} in the constructor initializer list of the copy constructor you get the mentioned output.
To solve this you should replace: auto i: c with auto &i: c or const auto &i: c as shown below:
for (const auto &i: c)
{
cout << i << endl;
}
Now the elements of the vector are not copied into i. Instead they are references to the object themselves and so you'll get your expected output.
I am trying to convince myself that objects in C++ have constant address during their lifetime. Here is a minimal working example:
#include <iostream>
#include <type_traits>
#include <vector>
class Class1
{
public:
Class1(unsigned int * pt);
unsigned int * val_pt;
};
Class1::Class1(unsigned int * pt)
:
val_pt(pt)
{}
class Class2
{
public:
Class2(std::vector<unsigned int> vec_);
std::vector<unsigned int> vec_of_ints;
Class1 class1_instance;
};
Class2::Class2(std::vector<unsigned int> vec_)
:
vec_of_ints(vec_),
class1_instance(Class1(&vec_of_ints[0]))
{}
int main() {
std::vector<unsigned int> vec_test(10, 2);
Class2 instance_class2(vec_test);
Class1 instance_class1 = instance_class2.class1_instance;
//both addresses are equal
std::cout<<"Address stored in instance_class1: "<<instance_class1.val_pt<<" ,address of first vec_element of instance_class2: "<<&(instance_class2.vec_of_ints)[0]<<std::endl;
instance_class2.vec_of_ints.resize(20);
//different addresses now
std::cout<<"Address stored in instance_class1: "<<instance_class1.val_pt<<" ,address of first vec_element of instance_class2: "<<&(instance_class2.vec_of_ints)[0]<<std::endl;
return 0;
}
My Class2 stores a vector of ints and an instance of Class1. Class1 stores the address of the vector of the Class2 instance.
I'd like to get the address of that vector, i.e. the address where the vector is stored on the stack. If my understanding is correct, the resize() function doesn't change that address on the stack but only the content of that address, i.e. where the vector points to in heap.
My overall goal is to show that any modifications of the vector in Class2 are "visible" in the stored pointer of Class1. So if I dereference the pointer in Class1 I will get the same integer value as when accessing the vector itself in Class2. That is because the address of member variables are constant during runtime.
But I guess something is wrong in my code, probably in the constructor where I pass 'vec[0]'. I think this is not the actual address of the vector in the stack but some address on the heap. How do I get the correct address?
Any input is appreciated!
What you're doing here is ungodly, and needs to stop. Consider this particularly terrible pattern:
class DataOwner {
public:
inline std::vector<uint32_t>& getData() { return data; }
private:
// I am safely tucked away
std::vector<uint32_t> data;
};
class I_Want_To_Work_On_Data {
public:
I_Want_To_Work_On_Data(DataOwner* owner) : owner(owner) {}
void doThing() {
auto& direct_ref_to_data = owner->getData();
for(auto& item : direct_ref_to_data) {
// This is just as fast as your direct pointer :/
}
}
private:
DataOwner* owner;
};
Returning mutable access to the data is somewhat bad, but it's far safer than the approach you are taking (in a single threaded environment a least). Performance is no worse than what you are attempting, but it is a lot safer. So what are you optimising this for exactly? How is your approach an improvement over this boring pattern?
Now you could argue that providing mutable access to the std::vector isn't wanted (i.e. don't allow any old code to resize the array), but that can easily be solved without resorting to dirty hacks.
#include <vector>
#include <cstdint>
class DataOwner {
public:
inline std::vector<uint32_t>::iterator begin()
{ return data.begin(); }
inline std::vector<uint32_t>::iterator end()
{ return data.end(); }
inline std::vector<uint32_t>::const_iterator begin() const
{ return data.begin(); }
inline std::vector<uint32_t>::const_iterator end() const
{ return data.end(); }
private:
// I am safely tucked away
std::vector<uint32_t> data;
};
class ConstAccess {
public:
ConstAccess(const DataOwner& owner) : owner(owner) {}
void doThing() {
for(const auto& item : owner) {
}
}
private:
const DataOwner& owner;
};
class MutableAccess {
public:
MutableAccess(DataOwner& owner) : owner(owner) {}
void doThing() {
for(auto& item : owner) {
}
}
private:
DataOwner& owner;
};
The performance is the same as with your approach, however this approach as the following advantages:
It won't crash in debug builds on this line: class1_instance(Class1(&vec_of_ints[0])), when the vector is empty, and you attempt to dereference NULL to find the address.
It won't crash when you attempt to dereference unsigned int * val_pt; after you've accidentally resized the array.
It won't allow you to accidentally do: delete [] val_pt
I'm not sure what conclusions you extracted from the comments and responses above.
I just wanted to make sure these were not among them:
The address of a member variable is constant during runtime.
If, for example, you have a vector of Class2 instances, and you
resize that vector, the address of the vec_of_ints member variable
may change for any of those instances.
Having a Class2 instance in the stack or a pointer to a Class2 instance in the heap makes a difference.
The address of the vec_of_ints member variable shouldn't change if
you resize it, no matter the instance of Class2 is in the stack or
in the heap.
The example below tests both assertions (https://godbolt.org/z/3TYrnjro8):
#include <iomanip>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
struct HoldsIntVector
{
std::vector<int> v{};
};
int main()
{
HoldsIntVector stackInstance{};
auto heapInstance{std::make_unique<HoldsIntVector>()};
stackInstance.v.push_back(5);
heapInstance->v.push_back(5);
auto printStackAndHeapInstances = [&](const auto& text){
std::cout << std::showbase << std::hex;
std::cout << &stackInstance << "\t" << &heapInstance << "\t";
std::cout << &stackInstance.v << "\t" << &heapInstance->v << "\t";
std::cout << std::setw(8) << std::setfill('0') << stackInstance.v.data() << "\t\t";
std::cout << std::setw(8) << std::setfill('0') << heapInstance->v.data() << "\t\t";
std::cout << text;
std::cout << "\n";
};
std::cout << "stackInstance\theapInstance\tstackInstance.v\theapInstance.v\t&stackInstance.v[0]\t&heapInstance.v[0]\n";
printStackAndHeapInstances("after initializing stack and heap instances");
// After resizing both vectors in stack and heap instances
//
// Address of v doesn't change neither in stack nor in heap instances
// Address of v[0] changes in both stack and heap instances
stackInstance.v.resize(10);
heapInstance->v.resize(10);
printStackAndHeapInstances("after resizing both v's");
std::cout << "\n";
// Now what happens if we have a vector of HoldsIntVector and we resize it
//
// Address of v changes for the first HoldsInVector
std::vector<HoldsIntVector> hivs{10};
std::for_each(begin(hivs), end(hivs), [](auto& hiv){hiv.v.push_back(3);});
std::cout << "&hivs[0].v\n" << &hivs[0].v << "\t" << "after intializing hivs\n";
hivs.resize(20);
std::cout << &hivs[0].v << "\t" << "after resizing hivs\n";
}
// Example program
#include <iostream>
#include <ostream>
#include <string>
#include <vector>
class One
{
public:
One(int age, int price)
: m_age(age), m_price(price)
{
std::cout << "m_age: " << m_age << " , m_price: " << m_price << std::endl;
}
One(const One&) = default;
One& operator=(const One&) = default;
int age() const { return m_age; }
int price() const { return m_price; }
private:
int m_age;
int m_price;
};
std::ostream& operator<<(std::ostream& os, const One& one)
{
os << "<< m_age: " << one.age() << " , m_price: " << one.price();
return os;
}
int main()
{
std::vector<One> vecOnes = {{1, 2}, {3, 4}};
//for(auto it: vecOnes) // case I
//for(auto& it: vecOnes) // case II
for(const auto& it: vecOnes) // case III
{
std::cout << it << std::endl;
}
}
All three cases output the same results as follows:
m_age: 1 , m_price: 2
m_age: 3 , m_price: 4
<< m_age: 1 , m_price: 2
<< m_age: 3 , m_price: 4
Question> which case is more efficient way to use auto?
Originally, I expect the auto will trigger the constructor of class One. But it doesn't show that way based on the output results.
Originally, I expect the auto will trigger the constructor of class One. But it doesn't show that way based on the output results.
It does trigger a constructor: the copy constructor. But you didn't instrument that one† so you don't see any output. The other two cases don't construct a new object, so will definitely be more efficient.
Note that there is also a fourth case for (auto&& it : vecOnes) {...} It will be equivalent to your second case here and also not create any new objects.
†Well now that you edited your question, it should be pretty clear that the one case does construct new objects and the others all do not.
The reality is, it depends...
If you've just got a vector of a built-in type, such as an int then you might as well use auto it as it's cheap to make a copy and you'll save a dereference every time you use the value. For classes this will invoke the copy constructor which may affect performance.
However, if you're vector is contains a class then in general it'll be more efficient to use auto &it or const auto &it in order to save creating a copy of the object. There's no cost advantage to using const over non-const, it just comes down to how you want to interact with the object.
To be more specific let's restrict the scope of the question to libstdc++ and Visual C++.
Consider the case when objects stored in a container have the following properties:
Copying and assignment can be expensive
Moving and swapping is cheap and never throws
Default constructor is cheap and never throws
Some of the containers may and will reallocate/move stored objects when elements are added or removed. In that case do the above mentioned STL implementations avoid copying when reallocating/moving elements?
What about std::sort and other algorithms?
If you think about it there is no need for copying when moving and swapping is available.
As you may know all STL operation provide Big O complexity guaranties. Big O means there is constant multiplied by some function of N. My question could be paraphrased by asking what does that constant include? Does it include the cost of copying or it is proportional to the cost of moving/swapping?
Thanks you.
The only general answer that can be given is that C++ is made by smart people that care a lot about performance so you usually won't find easy optimizations missed out and shouldn't worry too much about your standard library's performance.
You can answer these question type-by-type and function-by-function by reading the specification in the standard, websites like cppreference.com or the documentation that comes with your implementation. For example, if std::vector::push_back has to re-allocate its internal buffer, it will use the move constructor to “copy” over the elements if and only if such constructor exists and is declared noexcept (also see std::move_if_noexcept).
A different approach to reason about what is actually going on inside your standard library is taking it for a test drive. Instrument a simple struct to print out logging messages from its constructors and assignment operators, then put instances of that class into a standard library container and exercise some algorithm on it. The following example uses std::vector and std::sort. You can play with it by using different containers and algorithms. Also see what's happening if you make the changes indicated by the comments.
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <random>
#include <vector>
struct Example
{
int id;
Example(const int id) : id {id}
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Example(const Example& rhs) : id {rhs.id}
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
// try commenting out the 'noexcept'
Example(Example&& rhs) noexcept : id {rhs.id}
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Example&
operator=(const Example& rhs)
{
this->id = rhs.id;
std::cout << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
// try commenting out the 'noexcept'
Example&
operator=(Example&& rhs) noexcept
{
this->id = rhs.id;
std::cout << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
~Example() noexcept
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int
main()
{
const auto n = 10;
auto rndeng = std::default_random_engine {};
auto rnddst = std::uniform_int_distribution<int> {};
auto elements = std::vector<Example> {};
std::cout << "CONSTRUCTING VECTOR OF " << n << " ELEMENTS...\n\n";
elements.reserve(n); // try commenting this out
for (auto i = 0; i < n; ++i)
elements.emplace_back(rnddst(rndeng)); // try using push_back instead
const auto cmp = [](const Example& lhs, const Example& rhs){
return lhs.id < rhs.id;
};
std::cout << "\nSORTING ELEMENTS...\n\n";
std::sort(elements.begin(), elements.end(), cmp);
std::cout << "\nSORTED ELEMENTS:\n\n";
for (const auto& elem : elements)
std::cout << std::setw(16) << elem.id << "\n";
std::cout << "\nLEAVING MAIN...\n\n";
}
I have a class Model:
class Model
{
...
boost::shared_ptr<Deck> _deck;
boost::shared_ptr<CardStack> _stack[22];
};
Deck inherits from CardStack.
I tried to make _stack[0] point to the same thing that _deck points to by going:
{
_deck = boost::shared_ptr<Deck>(new Deck());
_stack[0] = _deck;
}
It seems that the assignment to _deck of _stack[0] results in a copy of _deck being made. (I know this because modifications to _stack[0] do not result in modifications to _deck.) How can I get them to point to the same thing?
Ok - no copy constructor is being called. I have verified this by implementing it and seeing if it gets called - it doesn't.
However - I have a function that operates on CardStack objects:
void TransferSingleCard(CardStack & src, CardStack & dst, Face f)
{
if( !src._cards.empty() )
{
src._cards.back().SetFace(f);
dst.PushCard(src._cards.back());
src._cards.pop_back();
}
}
Now - when I call:
{
TransferSingleCard(*_stack[DECK], _someotherplace, FACEDOWN);
std::cout << *_stack[DECK];
std::cout << *_deck;
}
I get this output (where std::cout on a CardStack will print out the size of that stack):
Num(103) TOP
Num(104) TOP
... so I've concluded (incorrectly?) that _stack[DECK] points to something different.
The Deck
class Deck : public CardStack
{
public:
Deck(int numsuits=2, StackIndex index = NO_SUCH_STACK );
Deck::Deck( const Deck & d);
int DealsLeft() const;
void RecalcDealsLeft();
private:
int _dealsleft;
};
Not clear what you are asking about - consider this code:
#include <iostream>
#include "boost/shared_ptr.hpp"
using namespace std;
struct A {
virtual ~A() {
cout << "destroyed" << endl;
}
};
struct B : public A {
};
int main() {
boost::shared_ptr<B> b( new B );
boost::shared_ptr<A> a;
a = b;
}
Only one "destroy" message appears, indicating that no copy has been made.
This example - derives from #Neil's answer, tries to emulate what you say is happening. Could you check that it works as expected (A and B have the same count) on your system.
Then we could try and modify this code or your code until they match.
#include <boost/shared_ptr.hpp>
#include <iostream>
class A {
public:
virtual ~A()
{
std::cerr << "Delete A" << std::endl;
}
int _count;
void decrement()
{
_count --;
}
};
class B : public A {
public:
virtual ~B()
{
std::cerr << "Delete B" << std::endl;
}
};
int main()
{
boost::shared_ptr<B> b(new B);
b->_count = 104;
boost::shared_ptr<A> a;
a = b;
a->decrement();
std::cerr << "A:" << a->_count << std::endl;
std::cerr << "B:" << b->_count << std::endl;
return 0;
}
EDIT:
So from the comment, we know the original pointers are correct, so now we need to trace.
Either:
log pointers to see when they change.
Use watchpoints in a debugger to see when the pointer changes.
Use a third shared pointer to see which pointer is changed.
Introduce a function that changes both pointers at the same time.
I think the problem is that you're assigning between different types here. boost::shared_ptr is a template and templates are not polymorphic even if the type in them is. So what's happening is that your compiler sees the assignment from boost::shared_ptr<Deck> to boost::shared_ptr<CardStack> and notices that it can make the assignment by calling the copy constructor for CardStack to duplicate the Deck object.
I think what you want the assignment to look like is something like this:
_stack[0] = boost::static_pointer_cast<CardStack>(_deck);
Which will do the conversion the way you expect it to.
I think you may want shared_array for _stack . . . Take a look at the documentation on shared_ptr;from boost.org, specifically:
http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/shared_ptr.htm
"Normally, a shared_ptr cannot
correctly hold a pointer to a
dynamically allocated array. See
shared_array for that usage."
Also, be aware of the T* get() function (not to be used without good reason) which returns the raw pointer being held by the managed pointer (shared_ptr in this case).