Consider the following data structures and code.
struct Sentence {
std::string words;
int frequency;
Sentence(std::string words, int frequency) : words(words), frequency(frequency) {}
};
struct SentencePCompare {
bool operator() (const Sentence* lhs, const Sentence* rhs) const {
if (lhs->frequency != rhs->frequency) {
return lhs->frequency > rhs->frequency;
}
return lhs->words.compare(rhs->words) < 0;
}
};
std::set<Sentence*, SentencePCompare> sentencesByFrequency;
int main(){
Sentence* foo = new Sentence("foo", 1);
Sentence* bar = new Sentence("bar", 2);
sentencesByFrequency.insert(foo);
sentencesByFrequency.insert(bar);
for (Sentence* sp : sentencesByFrequency) {
std::cout << sp->words << std::endl;
}
foo->frequency = 5;
for (Sentence* sp : sentencesByFrequency) {
std::cout << sp->words << std::endl;
}
}
The output of the above code is the following.
bar
foo
bar
foo
As we might expect, when an object pointed to by the pointer in the set is updated, the set does not automatically re-evaluate the predicate, even though the predicate orders the pointers based on the objects they point at.
Is there a way to force the std::set to re-evaluate the predicates, so that the order is correct again?
No.
There's a reason why set only allows const access to its elements. If you sneak past that by using shallow-const pointers and custom predicates and then destroy the invariant by modifying the pointee in a way that affects ordering, you'll pay the price in the form of nasal demons.
Before C++17, you need to erase and insert again, which incurs a key copy plus node deallocation and allocation. After, you can extract the node, modify it, and reinsert it, which is free.
Related
Guys I have a function like this (this is given and should not be modified).
void readData(int &ID, void*&data, bool &mybool) {
if(mybool)
{
std::string a = "bla";
std::string* ptrToString = &a;
data = ptrToString;
}
else
{
int b = 9;
int* ptrToint = &b;
data = ptrToint;
}
}
So I want to use this function in a loop and save the returned function parameters in a vector (for each iteration).
To do so, I wrote the following struct:
template<typename T>
struct dataStruct {
int id;
T** data; //I first has void** data, but would not be better to
// have the type? instead of converting myData back
// to void* ?
bool mybool;
};
my main.cpp then look like this:
int main()
{
void* myData = nullptr;
std::vector<dataStruct> vec; // this line also doesn't compile. it need the typename
bool bb = false;
for(int id = 1 ; id < 5; id++) {
if (id%2) { bb = true; }
readData(id, myData, bb); //after this line myData point to a string
vec.push_back(id, &myData<?>); //how can I set the template param to be the type myData point to?
}
}
Or is there a better way to do that without template? I used c++11 (I can't use c++14)
The function that you say cannot be modified, i.e. readData() is the one that should alert you!
It causes Undefined Behavior, since the pointers are set to local variables, which means that when the function terminates, then these pointers will be dangling pointers.
Let us leave aside the shenanigans of the readData function for now under the assumption that it was just for the sake of the example (and does not produce UB in your real use case).
You cannot directly store values with different (static) types in a std::vector. Notably, dataStruct<int> and dataStruct<std::string> are completely unrelated types, you cannot store them in the same vector as-is.
Your problem boils down to "I have data that is given to me in a type-unsafe manner and want to eventually get type-safe access to it". The solution to this is to create a data structure that your type-unsafe data is parsed into. For example, it seems that you inteded for your example data to have structure in the sense that there are pairs of int and std::string (note that your id%2 is not doing that because the else is missing and the bool is never set to false again, but I guess you wanted it to alternate).
So let's turn that bunch of void* into structured data:
std::pair<int, std::string> readPair(int pairIndex)
{
void* ptr;
std::pair<int, std::string> ret;
// Copying data here.
readData(2 * pairIndex + 1, ptr, false);
ret.first = *reinterpret_cast<int*>(ptr);
readData(2 * pairIndex + 2, ptr, true);
ret.second = *reinterpret_cast<std::string*>(ptr);
}
void main()
{
std::vector<std::pair<int, std::string>> parsedData;
parsedData.push_back(readPair(0));
parsedData.push_back(readPair(1));
}
Demo
(I removed the references from the readData() signature for brevity - you get the same effect by storing the temporary expressions in variables.)
Generally speaking: Whatever relation between id and the expected data type is should just be turned into the data structure - otherwise you can only reason about the type of your data entries when you know both the current ID and this relation, which is exactly something you should encapsulate in a data structure.
Your readData isn't a useful function. Any attempt at using what it produces gives undefined behavior.
Yes, it's possible to do roughly what you're asking for without a template. To do it meaningfully, you have a couple of choices. The "old school" way would be to store the data in a tagged union:
struct tagged_data {
enum { T_INT, T_STR } tag;
union {
int x;
char *y;
} data;
};
This lets you store either a string or an int, and you set the tag to tell you which one a particular tagged_data item contains. Then (crucially) when you store a string into it, you dynamically allocate the data it points at, so it will remain valid until you explicitly free the data.
Unfortunately, (at least if memory serves) C++11 doesn't support storing non-POD types in a union, so if you went this route, you'd have to use a char * as above, not an actual std::string.
One way to remove (most of) those limitations is to use an inheritance-based model:
class Data {
public:
virtual ~Data() { }
};
class StringData : public Data {
std::string content;
public:
StringData(std::string const &init) : content(init) {}
};
class IntData : public Data {
int content;
public:
IntData(std::string const &init) : content(init) {}
};
This is somewhat incomplete, but I think probably enough to give the general idea--you'd have an array (or vector) of pointers to the base class. To insert data, you'd create a StringData or IntData object (allocating it dynamically) and then store its address into the collection of Data *. When you need to get one back, you use dynamic_cast (among other things) to figure out which one it started as, and get back to that type safely. All somewhat ugly, but it does work.
Even with C++11, you can use a template-based solution. For example, Boost::variant, can do this job quite nicely. This will provide an overloaded constructor and value semantics, so you could do something like:
boost::variant<int, std::string> some_object("input string");
In other words, it's pretty what you'd get if you spent the time and effort necessary to finish the inheritance-based code outlined above--except that it's dramatically cleaner, since it gets rid of the requirement to store a pointer to the base class, use dynamic_cast to retrieve an object of the correct type, and so on. In short, it's the right solution to the problem (until/unless you can upgrade to a newer compiler, and use std::variant instead).
Apart from the problem in given code described in comments/replies.
I am trying to answer your question
vec.push_back(id, &myData<?>); //how can I set the template param to be the type myData point to?
Before that you need to modify vec definition as following
vector<dataStruct<void>> vec;
Now you can simple push element in vector
vec.push_back({id, &mydata, bb});
i have tried to modify your code so that it can work
#include<iostream>
#include<vector>
using namespace std;
template<typename T>
struct dataStruct
{
int id;
T** data;
bool mybool;
};
void readData(int &ID, void*& data, bool& mybool)
{
if (mybool)
{
data = new string("bla");
}
else
{
int b = 0;
data = &b;
}
}
int main ()
{
void* mydata = nullptr;
vector<dataStruct<void>> vec;
bool bb = false;
for (int id = 0; id < 5; id++)
{
if (id%2) bb = true;
readData(id, mydata, bb);
vec.push_back({id, &mydata, bb});
}
}
I am trying to write an algorithm to check if a graph is connected, (building a board game in which the map is contained as a graph where Regions are Vertices and Borders are edges).
Each region contains a vector of regions that are its neighbors (vector neighbors).
I build the map and check if its connected in the main() function here:
int main()
{
Map map;
Region r1("R1");
Region r2("R2");
Region r3("R3");
r1.addNeighbor(r2);
r2.addNeighbor(r1);
r2.addNeighbor(r3);
r3.addNeighbor(r2);
map.addRegion(r1);
map.addRegion(r2);
map.addRegion(r3);
map.traversal(r1);
map.isConnected();
return 0;
}
And here is my traversal() and isConnected() method implementation:
void Map::traversal(Region currentNode)
{
visited.push_back(currentNode.getRegionName());
Region* current = ¤tNode;
cout << (*current).getRegionName() << " loc: " << current << endl;
for (auto const & neighbor : (currentNode).getNeighbors())
{
if (std::find(visited.begin(), visited.end(), neighbor.getRegionName()) != visited.end()) {
}
else {
cout << (neighbor).getRegionName() << " neighbors: " << (neighbor).getNeighbors().size() << " location: " << &(neighbor) << endl;
traversal(neighbor);
}
}
}
bool Map::isConnected()
{
cout << visited.size() << endl;
cout << regions.size() << endl;
vector<string> regionList;
for (int i = 0; i < regions.size(); i++)
{
regionList.push_back(regions[i].getRegionName());
}
if (visited.size() == regionList.size())
{
return true;
}
else
{
return false;
}
}
The issue I have here is that for some reason, when I get the neighbors of nodes other than the starting node during the recursion of the traversal function, the function for some reason sometimes no longer remembers the neighbors of the current node being traversed (the output of the (neighbor).getNeighbors().size() will sometimes be equal to 0). Also, the address of the currentNode is not always the same as the address of the original object being referenced, leading me to believe that it is copying the object rather than directly pointing to its memory location.
Any help would be appreciated. I am still very new to C++ and the concept of pointers.
Here's the code for my Region class by request:
Region.h
#pragma once
#include <string>
#include <vector>
using namespace std;
class Region
{
private:
string owner;
string regionName;
int numTokens;
public:
vector<Region> neighbors;
void setOwner(string playerName);
void setRegionName(string name);
void setNumTokens(int num);
void addNeighbor(Region r);
vector<Region> getNeighbors() const;
string getOwner() const;
string getRegionName() const;
int getNumTokens() const;
Region();
Region(string regionName);
~Region();
};
Region.cpp
#include "stdafx.h"
#include "Region.h"
Region::Region()
{
}
Region::Region(string name)
{
regionName = name;
owner = "none";
numTokens = 0;
}
Region::~Region()
{
}
void Region::setOwner(string playerName)
{
playerName = owner;
}
string Region::getRegionName() const
{
return regionName;
}
int Region::getNumTokens() const
{
return numTokens;
}
void Region::setRegionName(string name)
{
regionName = name;
}
void Region::setNumTokens(int num)
{
numTokens = num;
}
void Region::addNeighbor(Region r)
{
neighbors.push_back(r);
}
vector<Region> Region::getNeighbors() const
{
return neighbors;
}
string Region::getOwner() const
{
return owner;
}
In
void Map::traversal(Region currentNode)
currentNode is passed by value. This means currentNode is independent of and (anywhere it matters) a copy of the Region provided as a parameter when invoking traversal. This is the different addresses you are noting with
cout << (*current).getRegionName() << " loc: " << current << endl;
Fix with
void Map::traversal(Region & currentNode)
although
void Map::traversal(const Region & currentNode)
is preferred if you do not intend on changing currentNode inside the function (or as a result of the function). It prevents mistakes, and since you have promised not to change the provided Region, the compiler can take advantage of some tricks and optimizations.
The next boobytrap is
vector<Region> neighbors;
stores copies of whatever is placed in them, not the original. So
r1.addNeighbor(r2);
calls
void Region::addNeighbor(Region r)
which is also pass by value (r is a copy of r2) and
neighbors.push_back(r);
places a copy of r into the vector. End result is r1 does not really know r2, it knows a copy. Modifying r2 after the copy does not effect the copy. You are trapped. You must store pointers.
Region needs to look something more like
class Region
{
private:
string owner;
string regionName;
int numTokens;
public:
vector<Region *> neighbors; // change here
void setOwner(string playerName);
void setRegionName(string name);
void setNumTokens(int num);
void addNeighbor(Region * r); // change here
vector<Region *> getNeighbors() const; // change here
string getOwner() const;
string getRegionName() const;
int getNumTokens() const;
Region();
Region(string regionName);
// ~Region(); not required.
};
Unrelated: Region contains no resources that are not self managed and as a result can take advantage of The Rule of Zero. You can safely remove its destructor. Yes. I know it contains a vector of raw pointers. More on this below.
This can lead you into a memory management nightmare, so you have to make sure you have ownership of those Regions everyone is pointing at nailed down.
Ownership is basically "Who's responsible for the clean-up? Who makes sure what's being pointed at is freed when its no longer required?"
In the case of your example,
Region r1("R1");
Is an Automatic variable. It manages it's own lifetime. It is released when it goes out of scope. You can
r1.addNeighbor(&r2); //pass raw pointer to r2
and r2 will be destroyed on schedule right before r1, which if you think about it is kinda dangerous. r1 still holds a pointer to r2, but r1 is also going out off scope, so you'd need to do something stupid in the destructor or go multi threaded. Region doesn't need a destructor, so you're safe, and if you are multi threaded a whole new set of assumptions are required, like why are you going out of scope in main while you still have threads running?
But what about less trivial cases where you're adding and removing Regions and reshaping the graph dynamically?
This gets ugly fast.
Often people will elect to go with a smart pointer in neighbors to manage the
memory for them. Doesn't work well in your case. Doesn't work well for them in a lot of cases, either.
vector<unique_ptr<Region>> (one-and-only-one pointer) doesn't make any sense because there can be many Regions all pointing at the same Region. So much for uniqueness.
shared_ptr also doesn't make sense because r1 points to r2 and r2 points back to r1. Direct action will have to be taken to eliminate the cycle and this mostly defeats the point of a smart pointer. What if you forget or get derailed by an exception?
There are games one can play with weak_ptr, but in a bidirectional graph who is the shared and who is the weak?
Opinion Warning: I favour Regions using raw pointers and a master list of Regions (vector<unique_ptr<Region>> again, but this time it works) as a member of a Graph class that manages access, insertion, removal, and all the other manipulations the same way you would with a linked list managing the linked nodes.
There may be sharper solutions out there that I'm not seeing.
Edit: Here's one based on M.M.'s comment
class Region
{
private:
string owner;
string regionName;
int numTokens;
public:
vector<string> neighbors; // change here. If you have large numbers of neighbours
// consider using a std::set in place of the vector
void setOwner(string playerName);
void setRegionName(string name);
void setNumTokens(int num);
void addNeighbor(const string & name); // change here. Accepting const reference
// reduces unnecessary copying. May want
// to use the same trick for other methods
// receiving a string
const vector<string> & getNeighbors() const; // change here. Returning const
// reference reduces unnecessary copying
string getOwner() const;
string getRegionName() const;
int getNumTokens() const;
Region();
Region(string regionName);
// ~Region(); not required.
};
This assumes regionName is unique and uses it as the key to access the Region from a master list that looks something like map<string, Region> masterlist;. masterlist manages storage for all of your Regions. Remove a Region from it and If the regionName cannot be found in masterlist you don't have to worry about invalid pointers, you just take note and remove it from neighbors.
Remember to be careful with the subscript operator. In masterlist[name] if name cannot be found, a Region will be default constructed for it and stored. Prefer to use the find method if you are looking for a Region that should exist.
If you have a fixed number of regions, consider using a simple array or std::array in place of the map for masterlist and use the index of the Region in the array as the identifier in place of string.
Supplemental reading: What's the difference between passing by reference vs. passing by value?
I'm having a problem getting the desired behaviour with array subscription and assignment.
Is there any way to determine whether assignment is used with array subscription?
EDIT
My question probably should have been, can I map [] to a getter, and []= to a setter
// Expect this to return a reference to the value if the key exists,
// or throw an exception if not
myMap["Key"];
// Expect this to always return a reference to the value
// so the value can be populated
myMap["Key"] = "Value";
// The method being used
template <typename K, typename V>
V& MyMap<K, V>::operator[](const K &key)
{
if(this->keyExists(key))
{
return this->find(key);
}
else
{
// At this point I'd like to throw an exception if
// assignment is not being used
this->insert(key, NULL);
return this->pairs[this->itemsStored].val;
}
};
Is there any way to determine whether assignment is used with array
subscription?
Simply, no.
When you do:
myMap["Key"] = "Value";
You're calling two member functions: first, map::operator[] and then -- on a totally different class -- key::operator=. When you simply do myMap["Key"] without the assignment nothing has changed with regards to how you interface with the map. The only difference is what you do next.
You could, I suppose, find some technical hack (like providing a const and non-const version that do different things) which will provide the behavior you are trying to achieve -- but it will be at the cost of poor design. Since you have perscribed within the non-const version that a missing key will be added, subsequently throwing in the non-const version is a major difference. This will be a nightmare to maintain. You will have very strange bugs arise when one version is actually being called when you expected the other to be called. People using your code will be confused and curse your name. Don't do it.
Instead, I suggest you're barking up the entirely wrong tree to begin with. Instead of trying to use operator[] const to determine the existence of a key, why not simply provide a member function that does simply that?
You can, if you wish, have this function throw if the key doesn't exist or simply return a bool.
There's only one way to be sure that no operator= will be called after operator[] (by overloading an operator[] const function), but that wouldn't work every time.
As there's no (easy) way to be able to know when an operator[] is being called with the operator= right after, I'd suggest you to follow the example of std::map by providing two different functions:
operator[], which always return a reference to the object; if the object does not exists, it is created
at, which returns a reference only if the object is already there, otherwise it throws an exception of type std::out_of_range
Yes. Just have the operator[] return a proxy. Something like
the following should work. (I'm using std::map for the
implementation; you can map it to whatever you're using)
template <typename KeyType, typename MappedType>
class MyMap
{
std::map<KeyType, MappedType> myImpl;
// ...
public:
void set( KeyType const& key, MappedType const& value )
{
myImpl[key] = value;
}
MappedType get( KeyType const& key )
{
auto entry = myImpl.find( key );
if ( entry == myImpl.end() ) {
throw DesiredException();
}
return entry->second;
}
class Proxy
{
MyMap* myOwner;
Key myKey;
publc:
Proxy( MyMap& owner, Key const& key )
: myOwner( &owner )
, myKey( key )
{
}
Proxy const& operator=( MappedType const& value ) const
{
myOwner->set( myKey, value );
return *this;
}
operator MappedType() const
{
return myOwner->get( myKey );
}
};
Proxy operator[]( KeyType const& key )
{
return Proxy( *this, key );
}
MappedType operator[]( KeyType const& key ) const
{
return get( key );
}
};
I'm not sure that this is a good idea, however. In general,
having a get( KeyType ) which returns a pointer to the mapped
element, or a null pointer if it isn't present, seems more
natural in C++.
DISCLAIMER : what follows is bad practice, and I do not recommend actually using this. It's merely here to show that what the OP wants is technically possible, even though it's a really bad idea (for reasons I'll go into further).
The bad idea
If you don't mind a bit of hassle, you can have a const and a non-const version of operator[] that behave differently. The const version would throw an exception when accessing a non-existent item, while the non-const version would default-construct a new item in that case.
As a proof of concept :
#include <iostream>
#include <stdexcept>
class Map {
public :
int value;
Map() { value = 42; }
const int& operator[](const size_t& pos) const { if (pos == 0) return value; else throw std::runtime_error("oops"); }
int& operator[](const size_t& pos) { return value; }
};
void showValue(const Map& myMap, size_t pos) {
try {
std::cout << "myMap[" << pos << "] = " << myMap[pos] << std::endl;
}
catch (std::runtime_error e) {
std::cout << "exception when accessing myMap[" << pos << "] : " << e.what() << std::endl;
}
}
int main(void) {
Map myMap;
showValue(myMap, 0);
showValue(myMap, 1);
myMap[0] = 5;
showValue(myMap, 0);
myMap[1] = 10;
showValue(myMap, 0);
return 0;
}
would print :
myMap[0] = 42
exception when accessing myMap[1] : oops
myMap[0] = 5
myMap[0] = 10
But the hassle I mentioned earlier, is to make sure the const version is used whenever the result won't be modified (in the example above, that's done by using a const reference).
Why it's bad
As mentioned at the beginning (and as pointed out by John Dibling in comments), this approach is not recommended. The problem is that :
it's difficult to know which version of operator[] will be called (in those cases where both can be called)
the two versions of operator[] behave differently (one throws an exception while the other would add a new item when called with the same argument)
Combine these two observations, and you get close to unpredictable behaviour, which will hurt you when you least expect it (trust me). And worse, it might be difficult to track down and fix such issues when they occur.
As a rule of thumb, the const and non-const versions of any member function should not differ in their core functionality. Violate that rule, and you invite the wrath of whoever has to maintain the code (and that probably includes your future self).
Any alternatives ?
So, don't do this. Instead, just either do it the same way std::map does (or better yet, just use std::map), or have a contains function you can call to check if an item exists.
How do I get the position of an element inside a vector, where the elements are classes. Is there a way of doing this?
Example code:
class Object
{
public:
void Destroy()
{
// run some code to get remove self from vector
}
}
In main.cpp:
std::vector<Object> objects;
objects.push_back( <some instances of Object> );
// Some more code pushing back some more stuff
int n = 20;
objects.at(n).Destroy(); // Assuming I pushed back 20 items or more
So I guess I want to be able to write a method or something which is a member of the class which will return the location of itself inside the vector... Is this possible?
EDIT:
Due to confusion, I should explain better.
void Destroy(std::vector<Object>& container){
container.erase( ?...? );
}
The problem is, how can I find the number to do the erasing...? Apparently this isn't possible... I thought it might not be...
You can use std::find to find elements in vector (providing you implement a comparison operator (==) for Object. However, 2 big concerns:
If you need to find elements in a container then you will ger much better performance with using an ordered container such as std::map or std::set (find operations in O(log(N)) vs O(N)
Object should not be the one responsible of removing itself from the container. Object shouldn't know or be concerned with where it is, as that breaks encapsulation. Instead, the owner of the container should concern itself ith such tasks.
The object can erase itself thusly:
void Destroy(std::vector<Object>& container);
{
container.erase(container.begin() + (this - &container[0]));
}
This will work as you expect, but it strikes me as exceptionally bad design. Members should not have knowledge of their containers. They should exist (from their own perspective) in an unidentifiable limbo. Creation and destruction should be left to their creator.
Objects in a vector don't automatically know where they are in the vector.
You could supply each object with that information, but much easier: remove the object from the vector. Its destructor is then run automatically.
Then the objects can be used also in other containers.
Example:
#include <algorithm>
#include <iostream>
#include <vector>
class object_t
{
private:
int id_;
public:
int id() const { return id_; }
~object_t() {}
explicit object_t( int const id ): id_( id ) {}
};
int main()
{
using namespace std;
vector<object_t> objects;
for( int i = 0; i <= 33; ++i )
{
objects.emplace_back( i );
}
int const n = 20;
objects.erase( objects.begin() + n );
for( auto const& o : objects )
{
cout << o.id() << ' ';
}
cout << endl;
}
If you need to destroy the n'th item in a vector then the easiest way is to get an iterator from the beginning using std::begin() and call std::advance() to advance how ever many places you want, so something like:
std::vector<Object> objects;
const size_t n = 20;
auto erase_iter = std::advance(std::begin(objects), n);
objects.erase(erase_iter);
If you want to find the index of an item in a vector then use std::find to get the iterator and call std::distance from the beginning.
So something like:
Object object_to_find;
std::vector<Object> objects;
auto object_iter = std::find(std::begin(objects), std::end(objects), object_to_find);
const size_t n = std::distance(std::begin(objects), object_iter);
This does mean that you need to implement an equality operator for your object. Or you could try something like:
auto object_iter = std::find(std::begin(objects), std::end(objects),
[&object_to_find](const Object& object) -> bool { return &object_to_find == &object; });
Although for this to work the object_to_find needs to be the one from the actual list as it is just comparing addresses.
This is a homework assignment. The Field container was the assignment from a week ago, and now I'm supposed to use the Field container to act as a dynamic array for a struct NumPair which holds two char * like so:
struct NumPair
{
char *pFirst, *pSecond;
int count;
NumPair( char *pfirst = "", char *psecond = "", int count = 0)
: pFirst(strdup(pfirst)), pSecond(strdup(psecond)), count(count)
{ }
NumPair( const NumPair& np )
: count(np.count), pFirst(strdup(np.pFirst)), pSecond(strdup(np.pSecond))
{ }
NumPair& operator=( const NumPair& np )
{
if(this != &np)
{
pFirst = strdup(np.pFirst);
pSecond = strdup(np.pSecond);
count = np.count;
}
return *this;
}
and the Field container
Field<NumPair> dict_;
The homework requires the use of char *, and not string, so that we can get better with all this low-level stuff. I've already had some question about char to wchar_t conversions, etc.
Now I have a question as to whether or not I'm destructing the NumPair properly. The scenario is as follows:
1) Field destructor gets called
template <class T>
Field<T>::~Field()
{
delete[] v_;
}
2) Delete calls the destructor of every element NumPair in v_;
~NumPair()
{
free(pFirst);
free(pSecond);
}
Is this okay? I haven't really read too many articles about mixing and matching elements created on the heap and free-store as we wish. I figure as long as I don't use delete on an improper malloc'ed element, I should be fine.
However, I don't know the entire intricacies of the delete command, so I'm wondering whether or not this is valid design, and what I could do to make it better.
Also, of course this isn't. I'm getting an error of the type:
This may be due to a corruption of the heap and points to dbgheap
extern "C" _CRTIMP int __cdecl _CrtIsValidHeapPointer(
const void * pUserData
)
{
if (!pUserData)
return FALSE;
if (!_CrtIsValidPointer(pHdr(pUserData), sizeof(_CrtMemBlockHeader), FALSE))
return FALSE;
return HeapValidate( _crtheap, 0, pHdr(pUserData) ); // Here
}
Again, how could I improve this without the use of string?
FIELD CTOR/Copy Ctor/Assignment
template <class T>
Field<T>::Field()
: v_(0), vused_(0), vsize_(0)
{ }
template <class T>
Field<T>::Field(size_t n, const T &val)
: v_(0), vused_(n), vsize_(0)
{
if(n > 0)
{
vsize_ = 1;
while(vsize_ < n)
vsize_ <<= 1;
v_ = new T[vsize_];
std::fill(v_, (v_ + vused_), val);
}
}
template <class T>
Field<T>::Field(const Field<T> &other)
: v_(new T[other.vsize_]), vsize_(other.vsize_), vused_(other.vused_)
{
std::copy(other.v_, (other.v_ + other.vused_), v_);
}
template <class T>
Field<T>& Field<T>::operator =(const Field<T> &other)
{
this->v_ = other.v_;
this->vused_ = other.vused_;
this->vsize_ = other.vsize_;
return *this;
}
FIELD MEMBERS
T *v_;
size_t vsize_;
size_t vused_;
Your copy constructor (of Field<>) seems OK, but the operator= is problematic.
Not only does it leak memory (what happens to the original v_?), but after that, two instances of Field<> hold a pointer to the same block of memory, and the one that is destructed first will invalidate the others v_ - and you can't even tell whether that has happened.
It's not always easy to decide how to deal with operator= - some think that implicit move semantics are okay, but the rest of us see how that played out with the majority of people, with std::auto_ptr. Probably the easiest solution is to disable copying altogether, and use explicit functions for moving ownership.
Your string handling in NumPair looks ok (strdup + free) and your Field container delete[] looks okay but it's hard to say because you don't show what v_ is.
eq mentions in a comment that you should also beware of how you are copying NumPairs. By default, C++ will give you an implicit member-wise copy constructor. This is where a RAII type like std::string makes your life easier: Your std::string containing struct can be copied without any special handling on your part and memory referenced in the string will be taken care of by the string's copy. If you duplicate your NumPair (by assigning it or returning it from a function for example) then the destruction of the temporary will free your strings out from under you.
Your copy constructor for Field just copies the pointers in v_. If you have two copies of a Field, all of the NumPairs in v_ will be deleted when the first Field goes out of scope, and then deleted again when the second one does.