Read access violation after shuffling vector multiple times - c++

For a school project I need to shuffle a vector with unique pointers.
However when I do this I get a read access violation error after some time.
I create the vector and then call the shuffle. This I do multiple times. I just create the vector with the values and shuffle it once and after a couple of times I get the read access violation error.
code
int RandomEngine::generateRandomInt(int minValue, int maxValue)
{
std::uniform_int_distribution<int> distribution(minValue, maxValue);
std::cout << "Random getal van " << minValue << " tot " << maxValue << std::endl;
return distribution(def_rand_engine);
}
void RandomEngine::shuffleCharacterCards(std::vector<std::unique_ptr<CharacterCard>>& cards)
{
// Succeeds once but with multiple swaps read access violation
//auto randomInt = generateRandomInt(0, cards.size() - 1);
//iter_swap(cards.begin() + randomInt, cards.begin());
// Read access violation
//for (int i = 0; i < cards.size(); i++)
//{
// std::swap(cards[i], cards[std::rand() % cards.size()]);
//}
// Read access violation
//std::shuffle(cards.begin(), cards.end(), std::mt19937{ def_rand_engine});
// Read access violation
//std::random_shuffle(cards.begin(), cards.end());
// Read access violation
//std::shuffle(cards.begin(), cards.end(), std::mt19937(std::random_device()()));
}
Other class where I call the shuffle from the static class
void CharacterCardStack::prepare()
{
std::cout << "Preparing CharacterCardStack..." << std::endl;
if(cards_.size() > 2)
{
// Shuffle the cards
RandomEngine::shuffleCharacterCards(cards_);
// Burn the first card
burnedCharacterCard_ = std::move(cards_[0]);
std::cout << "Burned charactercard: " << burnedCharacterCard_->getName() << std::endl;
cards_.erase(cards_.begin());
// Als de open kaart een koning is dan moet deze vervangen worden door een ander.
if(cards_[0]->getName() == "Koning")
{
turnedCharacterCard_ = std::move(cards_[1]);
}
else
{
turnedCharacterCard_ = std::move(cards_[0]);
}
std::cout << "Turned charactercard: " << turnedCharacterCard_->getName() << std::endl;
cards_.erase(cards_.begin());
}
else
{
std::cerr << "CharacterCardStack::prepare cards size is " << cards_.size() << std::endl;
throw std::exception("Error...");
}
for (const auto& c : cards_)
{
std::cout << "Other card: " << c->getName() << std::endl;
}
std::cout << "CharacterCardStack prepared" << std::endl;
}

You have flow in your logic, you move out either first or the second element based on condition:
if(cards_[0]->getName() == "Koning")
{
turnedCharacterCard_ = std::move(cards_[1]);
}
else
{
turnedCharacterCard_ = std::move(cards_[0]);
}
but then unconditionaly erase the first element:
cards_.erase(cards_.begin());
so you may end up with moved out pointers.
Simple fix could be:
if(cards_[0]->getName() == "Koning")
{
std::swap( cards_[0], cards_[1] );
}
turnedCharacterCard_ = std::move(cards_[0]);
std::cout << "Turned charactercard: " << turnedCharacterCard_->getName() << std::endl;
cards_.erase(cards_.begin());
this way it is easier to keep it correct and I would prefer use cards.front() instead of cards_[0], which is I think more readable in this case.

Related

Design pattern to create smart references to elements in a vector

Because references in a vector point to locations of memory and not the abstract element, it can cause a few problems when altering the memory of the vector.
If a reference points to an element in a vector, and then that element is shuffled to another spot in the vector, the reference doesn't track the element, and will point to incorrect data after the shuffle.
If a element is invalidated, you can still access that elements contents without any safety checks, if you declared a references before invalidating the element.
If the vector resizes, all current references may be invalidated.
I wrote an example program that demonstrates all three problems.
#include <iostream>
#include <vector>
struct entity { //Simple struct of data.
bool alive;
float data;
};
class manager {
std::vector<entity> vec;
size_t count; // Amount of currently alive entities
public:
//Reserves initial_amount of entities, all set to dead, count set to 0.
manager(size_t initial_amount) : vec(initial_amount, { false, 0.0f }), count(0) {}
entity& create(float f) {
vec[count] = {true, f};
return vec[count++];
}
void refresh() { //Two iterators, one starts at the front of the vector, the other at
size_t front = 0; //count. The front iterator searches for dead entities and swaps them
size_t back = count; //with alive entities from the back iterator. For each swap we decrement
//count by 1, with the final result being all alive entities are between
while(true) { //0 and count.
for( ; true; ++front) {
if (front > back) return;
if (!vec[front].alive) break;
}
for( ; true; --back) {
if (vec[back].alive) break;
if (back <= front) return;
}
std::swap(vec[back], vec[front]);
--count;
++front;
--back;
}
}
void grow(size_t n) {
vec.resize(n);
}
void print() { //Prints all alive entities.
for (size_t index = 0; index < count; index++)
std::cout << vec[index].data << " ";
std::cout << std::endl;
}
};
int main() {
using namespace std;
manager c(10);
entity& d1 = c.create(5.5);
entity& d2 = c.create(10.5);
entity& d3 = c.create(7.5);
// Correct behavior
cout << d1.data << endl; // 5.5
cout << d2.data << endl; // 10.5
cout << d3.data << endl; // 7.5
cout << endl;
d2.alive = false; // "Kill" the entity
c.refresh(); // removes all dead entities. (this will swap d2's and d3's data in the vector,
// but wont change the locations they point to)
// Oh no! d2 and d3 still point to the same locations in the vector and now their data
// is incorrect after the swap, also d2 is dead maybe that should just be an error.
cout << d1.data << endl; // 5.5
cout << d2.data << endl; // 7.5
cout << d3.data << endl; // 10.5
cout << endl;
c.print(); // Correct behavior, prints only alive entities.
cout << endl;
d3.data = 6.5; // Trying to change the value of d3, which should still be alive.
c.print(); // Error, because d3 still points to the 3rd slot the intended value hasn't been changed.
cout << endl;
c.grow(10000);
cout << d1.data << endl; // After resize all these references are invalidated,
cout << d2.data << endl; // and using them is undefined behavior.
cout << d3.data << endl;
return 0;
}
Is there a design pattern to create a smart reference or proxy type that solves these problems? An object that will track its elements position in the vector, does specific behavior if the element is alive or dead, and stay valid after a resize?
I'm fine with the implementation of the smart/proxy reference to not be an actual reference, could be a pointer, integer index, or whatever. But this is specifically for elements in a vector, not a linked-list, map, etc.
With std::vector<std::shared_ptr<entity>>, you may have the security you want:
class manager {
std::vector<std::shared_ptr<entity>> vec;
public:
//Reserves initial_amount of entities
explicit manager(size_t initial_amount) { vec.reserve(initial_amount); }
std::weak_ptr<entity> create(float f) {
vec.push_back(std::make_unique<entity>(entity{true, f}));
return vec.back();
}
void refresh() {
vec.erase(std::remove_if(vec.begin(), vec.end(),
[](const auto& ent) {return !ent->alive;}),
vec.end());
}
void grow(size_t n) { vec.reserve(n); }
void print() { //Prints all alive entities.
for (const auto& ent : vec)
std::cout << ent->data << " ";
std::cout << std::endl;
}
};
And then the test:
int main() {
manager c(10);
auto d1 = c.create(5.5);
auto d2 = c.create(10.5);
auto d3 = c.create(7.5);
// Correct behavior
if (auto e = d1.lock()) std::cout << e->data << std::endl; else std::cout << "Die\n"; // 5.5
if (auto e = d2.lock()) std::cout << e->data << std::endl; else std::cout << "Die\n"; // 10.5
if (auto e = d3.lock()) std::cout << e->data << std::endl; else std::cout << "Die\n"; // 7.5
std::cout << std::endl;
if (auto e = d2.lock()) e->alive = false; // "Kill" the entity
c.refresh(); // removes all dead entities.
if (auto e = d1.lock()) std::cout << e->data << std::endl; else std::cout << "Die\n"; // 5.5
if (auto e = d2.lock()) std::cout << e->data << std::endl; else std::cout << "Die\n"; // Die
if (auto e = d3.lock()) std::cout << e->data << std::endl; else std::cout << "Die\n"; // 10.5
std::cout << std::endl;
c.print(); // Correct behavior, prints only alive entities.
std::cout << std::endl;
if (auto e = d3.lock()) e->data = 6.5; // Trying to change the value of d3,
// which should still be alive.
c.print();
std::cout << std::endl;
c.grow(10000);
if (auto e = d1.lock()) std::cout << e->data << std::endl; else std::cout << "Die\n"; // 5.5
if (auto e = d2.lock()) std::cout << e->data << std::endl; else std::cout << "Die\n"; // Die
if (auto e = d3.lock()) std::cout << e->data << std::endl; else std::cout << "Die\n"; // 6.5
}
Demo

Not sure where the segmentation fault is

I'm getting problem with segmentation fault when trying to compile a C++ program, but not sure where the problem lies. I suspect that the problem lies with the .find() ..... could it be the iterator operator < and == which are the comparators for find() that is the issue? I hope that someone can point out to me where they think the problem lies.
The following is part of test01.cpp, where I run it to test the code and use print statements to find out where the problem is:
bool confirmEverythingMatches(const btree<long>& testContainer, const set<long>& stableContainer) {
cout << "Confirms the btree and the set "
"contain exactly the same values..." << endl;
for (long i = kMinInteger; i <= kMaxInteger; i++) {
cout << "Start of for-loop to find iterator for comparisons..." << endl;
if (stableContainer.find(i) != stableContainer.end()) {
cout << "can find i (" << i << ") in stableContainer!" << endl;
} else {
cout << "cannot find i (" << i << ") in stableContainer!" << endl;
}
cout << "In between finding i in stable and testContainers..." << endl;
if (testContainer.find(i) != testContainer.end()) {
cout << "can find i (" << i << ") in testContainer!" << endl;
} else {
cout << "cannot find i (" << i << ") in testContainer!" << endl;
}
cout << "Before assigning the find to boolean variables..." << endl;
bool foundInTree = (testContainer.find(i) != testContainer.end());
cout << "testContainer.find(i) != testContainer.end()" << endl;
bool foundInSet = (stableContainer.find(i) != stableContainer.end());
cout << "stableContainer.find(i) != stableContainer.end()" << endl;
if (foundInTree != foundInSet) {
cout << "- btree and set don't contain the same data!" << endl;
cout << "Mismatch at element: " << i << endl;
return false;
} else {cout << "foundInTree == foundInSet!!!" << i << endl;}
}
cout << "- btree checks out just fine." << endl;
return true;
}
} // namespace close
/**
* Codes for testing various bits and pieces. Most of the code is commented out
* you should uncomment it as appropriate.
**/
int main(void) {
// initialise random number generator with 'random' seed
initRandom();
cout << "after initRandom().." << endl;
// insert lots of random numbers and compare with a known correct container
btree<long> testContainer(99);
cout << "after specifying max node elements in testContainer.." << endl;
set<long> stableContainer;
cout << "after constructing stableContainer.." << endl;
insertRandomNumbers(testContainer, stableContainer, 1000000);
cout << "after inserting random numbers into testContainer and for success inserts, also into stableContainer.." << endl;
btree<long> btcpy = testContainer;
cout << "after copy assigning a copy of testContainer to btcopy.." << endl;
confirmEverythingMatches(btcpy, stableContainer);
cout << "after confirming everything internally matches between testContainer and stableContainer.." << endl;
return 0;
}
The output I get when running the program (No problem when compiling) is this:
Confirms the btree and the set contain exactly the same values...
Start of for-loop to find iterator for comparisons...
cannot find i (1000000) in stableContainer!
In between finding i in stable and testContainers...
ASAN:DEADLYSIGNAL
=================================================================
==7345==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000018 (pc 0x000108d132a8 bp 0x000000000000 sp 0x7fff56eee6f0 T0)
#0 0x108d132a7 in btree<long>::find(long const&) const (test01+0x1000022a7)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (test01+0x1000022a7) in btree<long>::find(long const&) const
==7345==ABORTING
Abort trap: 6
I also got this error when I tried to run it on another machine:
==29936==ERROR: AddressSanitizer failed to allocate 0x200000 (2097152) bytes of SizeClassAllocator32: 12
I found that when it goes into the find(), it will have the segmentation fault:
/**
* Identical in functionality to the non-const version of find,
* save the fact that what's pointed to by the returned iterator
* is deemed as const and immutable.
*
* #param elem the client element we are trying to match.
* #return an iterator to the matching element, or whatever the
* const end() returns if no such match was ever found.
*/
template<typename T> typename btree<T>::const_iterator
btree<T>::find(const T& elem) const {
std::cout << "CONST ITERATOR'S FIND" << std::endl;
Node *tmp_ = root_;
std::cout << "1" << std::endl;
while(true) {
std::cout << "2" << std::endl;
size_t i;
std::cout << "3" << std::endl;
// go through all elements from root to tail
for (i = 0; i < tmp_->__occupied_size_; ++i) {
std::cout << "4" << std::endl;
if (tmp_->__elem_[i] == elem) {
std::cout << "5" << std::endl;
// find the elem, return an iterator
return const_iterator(tmp_, i, this);
std::cout << "6" << std::endl;
} else if (tmp_->__elem_[i] > elem) {
std::cout << "7" << std::endl;
// elem is not in current Node, go to descendants
// for the elem.
if (tmp_->__descendants_ == nullptr) {
std::cout << "8" << std::endl;
return cend();
std::cout << "9" << std::endl;
} else {
std::cout << "10" << std::endl;
tmp_ = tmp_->__descendants_[i];
std::cout << "11" << std::endl;
break;
}
}
}
// handling boundaries cases
if (i == tmp_->__occupied_size_) {
std::cout << "12" << std::endl;
if (tmp_->__descendants_[i] == nullptr) {
std::cout << "13" << std::endl;
return cend();
std::cout << "14" << std::endl;
} else {
std::cout << "15" << std::endl;
tmp_ = tmp_->__descendants_[i];
}
}
}
}
The print statements for this find is:
CONST ITERATOR'S FIND
1
2
3
4
4
7
10
11
2
3
4
7
10
11
ASAN:DEADLYSIGNAL
Ok, so based on the implementation of this find function, I think the problem might be located in
if (tmp_->__descendants_ == nullptr) {
std::cout << "8" << std::endl;
return cend();
std::cout << "9" << std::endl;
} else {
std::cout << "10" << std::endl;
tmp_ = tmp_->__descendants_[i];
std::cout << "11" << std::endl;
break;
}
and then
// handling boundaries cases
if (i == tmp_->__occupied_size_) {
std::cout << "12" << std::endl;
if (tmp_->__descendants_[i] == nullptr) {
std::cout << "13" << std::endl;
return cend();
std::cout << "14" << std::endl;
} else {
std::cout << "15" << std::endl;
tmp_ = tmp_->__descendants_[i];
}
}
So, You are checking if tmp->__descendants_ is not null. If it is not, then you set tmp_ = tmp_->descendants_[i];
Note: you are just checking __descendants_ pointer to be null or not, you are not checking the __descendants_ [i] if it is null!
What if the tmp->__descendants_[i] is null (or gets out of the descendants array)?
If that value is null, then tmp_->occupied_size_ might give you segfault.
Note2: For some reason you are using same index "i" for iterating through __elem_ and __descendants_. I am not sure, how descendants are created, but it might be also a problem here.
This is why debuggers exist. Run your program in the debugger, let the program fail, and then the debugger will tell you where and why it's gone wrong.
It looks like you've got potentially a lot of code to trawl through, which no one here will really want to do as it's not a concise question.
Good luck!

Seemingly empty vector

I've added some slight multi threading to a simple c++ program and have encountered a few issues along the way.
The latest of these issues is that historical::assignthreads for some reason is receiving an empty vector from the function historical::writeData.
Looking at the code below you will see that writeData iterates through a vector and puts the data in a placeholder before sending it forward to assignthreads (after 5 iterations) - meaning that the vector being sent from writeData to assignthreads shouldn't be empty.
However in assignthreads you will see that there are two cout:s, one before and one after the loop. Both writes to cout without the loop even starting.
Does anyone have any idea of how this could be the case?
void historical::writeData(std::vector<std::vector<std::wstring>> in, const string& symbol) {
std::cout << "Sending data to database connector" << std::endl;
std::vector<std::vector<std::wstring>> temp;
std::vector<std::vector<std::wstring>>::iterator it;
int count = 0;
for (it = in.begin(); it != in.end(); it++) {
if (count = 5) {
cout << "I'm in count 5" << endl;
assignthreads(temp, symbol);
temp.clear();
count = 0;
}
else {
cout << "I'm in count 0" << endl;
temp.push_back(*it);
count++;
}
}
if (!temp.empty()) {
cout << "I'm in empty" << endl;
assignthreads(temp, symbol);
}
else cout << "I'm empty!!" << endl;
}
void historical::assignthreads(std::vector<std::vector<std::wstring>>& partVec, const string& symbol) {
int i = 0;
cout << "I'm in assign" << endl;
vector<thread> threads(size(partVec));
std::vector<std::vector<std::wstring>>::iterator it;
for (it = partVec.begin();
it != partVec.end();
it++) {
cout << "I'm in the loop" << endl;
std::shared_ptr<database_con> sh_ptr(new database_con);
threads.at(i) = std::thread(&database_con::start, sh_ptr, *it, symbol);
i++;
}
cout << "I've finished" << endl;
for (auto& th : threads) th.join();
}
void historical::writer(string* pInput) {
ofstream mf("test.csv");
if (mf.is_open()) {
mf << *pInput;
mf.close();
}
else cout << "Unable to open file" << endl;
}
Your fundamental problem here is that count = 5 is an assignment and is therefore always true. You intended to use count == 5.
It's worth noting that particularly as your vector becomes large copying it is very wasteful, and you're doing this 2 ways:
The vector is passed into writeData by value, change to copying by reference: void writeData(std::vector<std::vector<std::wstring>>& in, const string& symbol)
temp will eventually copy every element of in, use iterators instead so your code would have to change to:
#define SIZE 5
void assignthreads(std::vector<std::vector<std::wstring>>::iterator start, std::vector<std::vector<std::wstring>>::iterator finish, const string& symbol) {
cout << "I'm in assign" << endl;
vector<thread> threads(distance(start, finish));
for(auto i = 0; start != finish; ++i, ++start) {
cout << "I'm in the loop" << endl;
std::shared_ptr<database_con> sh_ptr(new database_con);
threads.at(i) = std::thread(&database_con::start, sh_ptr, *start, symbol);
}
cout << "I've finished" << endl;
for (auto& th : threads) th.join();
}
void writeData(std::vector<std::vector<std::wstring>>& in, const string& symbol) {
std::cout << "Sending data to database connector" << std::endl;
auto count = 0;
while(count < in.size() - SIZE) {
auto start = next(in.begin(), count);
count += SIZE;
auto finish = next(in.begin(), count);
assignthreads(start, finish, symbol);
}
assignthreads(next(in.begin(), count), in.end(), symbol);
cout << "I'm empty!!" << endl;
}

Possible bug in std::unordered_map

I was trying to find the culprit behind a segfault. My debugger told be that there was no data for variable that the error was at. Every 10 seconds, there is a little script in my C++ code that runs. It does "garbage collection" and deletes some "sessions" that are probably dead.
To perform this efficiently, I use a timestamp -- when was the data last accessed. If the data is more than 10 seconds old, it is dead. There is a keepalive command that triggers every 4 seconds on the client.
To perform this GC, I loop through an std::unordered_map and substract the current time since epoch from the time stored as the value in that pair. If the time is too large, I add it to an std::vector that holds the keys to be deleted (yeah, I know it can be optimized to skip this step).
The problem that I was facing is that it loops right the first time. However, thereafter, I get a segfault, which points to the iterator value to be greater than size of the map.
Just switching back over to a standard std::map fixed the entire problem!
I shall attach the function that does all of this. All of the code is available at http://github.com/yash101/DrawingPad
Now, the code [{sourcedir}/source/Session.cxx]:
void SessionHost::cron()
{
while(true)
{
std::this_thread::sleep_for(std::chrono::seconds(10));
if(DEBUG)
{
std::cout << "Cron has started!" << std::endl;
}
while(!locky_thingy.try_lock_for(std::chrono::milliseconds(MUTEX_TIMEOUT)))
{}
int timethrough = 0;
std::vector<std::string> del;
for(std::map<std::string, long>::iterator ite = timestamp.begin(); ite != timestamp.end(); ++ite)
{
timethrough++;
std::cout << "Time through: " << timethrough << std::endl;
std::string curkey = ite->first;
long curval = ite->second;
std::cout << "Key: " << curkey << std::endl;
if(DEBUG)
{
std::cout << "Checking " << curkey << " with old ts of " << curval << std::endl;
}
u_int64_t curtm = std::chrono::duration_cast<std::chrono::milliseconds> (std::chrono::system_clock::now().time_since_epoch()).count();
if(DEBUG)
{
std::cout << "Current time: " << curtm << std::endl;
}
if(curtm - curval > SESSION_TIMEOUT)
{
if(DEBUG)
{
std::cout << "Deleted session handle: [" << curkey << "]" << std::endl;
}
del.push_back(curkey);
}
else
{
if(DEBUG)
{
std::cout << "Kept back session handle: [" << curkey << "]" << std::endl;
}
}
for(unsigned int i = 0; i < del.size(); i++)
{
timestamp.erase(del[i]);
data.erase(del[i]);
std::cout << "Erasing: " << del[i] << std::endl;
}
}
locky_thingy.unlock();
}
}
You have:
for(std::map<std::string, long>::iterator ite = timestamp.begin();
ite != timestamp.end(); ++ite)
{
// ...
for(unsigned int i = 0; i < del.size(); i++)
{
timestamp.erase(del[i]); // <--
// ...
}
}
In an unordered_map, erasing can invalidate iterators. So you can't erase while you're traversing - try to come up with a different algorithm. (I'm assuming some version of your question involves timestamp being an unordered_map - although there's no reference to this type in your code).
I think the error is here
for(unsigned int i = 0; i < del.size(); i++)
{
timestamp.erase(del[i]);
data.erase(del[i]);
std::cout << "Erasing: " << del[i] << std::endl;
}
} // <---------------- this is the end of the iterator loop
It should be moved up before the for loop so it doesn't invalidate.
} // <---------------- this is the end of the iterator loop
for(unsigned int i = 0; i < del.size(); i++)
{
timestamp.erase(del[i]);
data.erase(del[i]);
std::cout << "Erasing: " << del[i] << std::endl;
}
The data.erase might also have a fault if it is a vector.
If you have a vector you need to erase for you should mark the records and use
data.erase(std::remove_if(data.begin(), data.(end), CheckMark));
remove_if moves all valid data to the start of data, erase then erases from after the last valid.

how to use exceptions and pointers in a vector class

I have this vector class, and I was provided with a driver to test the class. Most of it seems to work fine but I think there is something wrong with the exceptions part (which I haven't quite fully understood)
Here is the code for the class .cpp file
int myVector::at(int i)
{
if(i<vsize)
return array[i];
throw 10;
}
and here is the driver code
#include "myVector.h"
#include <iostream>
using namespace std;
int main()
{
// Create a default vector (cap = 2)
myVector sam;
// push some data into sam
cout << "\nPushing three values into sam";
sam.push_back(21);
sam.push_back(31);
sam.push_back(41);
cout << "\nThe values in sam are: ";
// test for out of bounds condition here
for (int i = 0; i < sam.size( ) + 1; i++)
{
try
{
cout << sam.at(i) << " ";
}
catch(int badIndex)
{
cout << "\nOut of bounds at index " << badIndex << endl;
}
}
cout << "\n--------------\n";
// clear sam and display its size and capacity
sam.clear( );
cout << "\nsam has been cleared.";
cout << "\nSam's size is now " << sam.size( );
cout << "\nSam's capacity is now " << sam.capacity( ) << endl;
cout << "---------------\n";
// Push 12 values into the vector - it should grow
cout << "\nPush 12 values into sam.";
for (int i = 0; i < 12; i++)
sam.push_back(i);
cout << "\nSam's size is now " << sam.size( );
cout << "\nSam's capcacity is now " << sam.capacity( ) << endl;
cout << "---------------\n";
cout << "\nTest to see if contents are correct...";
// display the values in the vector
for (int i = 0; i < sam.size( ); i++)
{
cout << sam.at(i) << " ";
}
cout << "\n--------------\n";
cout << "\n\nTest Complete...";
cout << endl;
system("PAUSE");
return 0;
}
Any help is appreciated. Thanks
The driver that you have provided:
try {
cout << sam.at(i) << " ";
}
catch(int badIndex) {
cout << "\nOut of bounds at index " << badIndex << endl;
}
expects that int will be thrown (a bit weird design, but well... this is the code that will use your class...). Your implementation of at() might look like this:
int& myVector::at(int i) throw(int) {
if (i < vsize)
return array[i];
throw i;
}
just try to follow one simple rule: throw by value, catch by reference.
Also note that you have a pointer:
private:
int* array;
which points to dynamically allocated memory allocated in constructor and copy constructor and freed in destructor :
myVector::myVector(int i)
{
...
array = new int[maxsize];
}
myVector::myVector(const myVector& v)//copy constructor
{
...
array =new int[maxsize];
}
myVector::~myVector()
{
delete[] array;
}
But how about the assignment operator ? See What is The Rule of Three?
Your stop condition of for loop ends it one element after the last one (i.e. you cannot access 4th element of sam vector because there are only three elements).
std::vector::at throws std::out_of_range exception in such situation (see: http://en.cppreference.com/w/cpp/container/vector/at), not int one. So you should change your exception handling part to something like this:
#include <exception>
try
{
cout << sam.at(i) << " ";
}
catch(std::out_of_range exc)
{
cout << "\nOut of bounds at index " << exc.what() << endl;
}