Copying column info in C++ - c++

I have to copy column info from a database to a struct, the problem is that it takes over 5000 iterations and is very slow. Is there any better way?
The code used is in the .h file:
struct sFieldDef
{
CString m_strQualifier;
CString m_strOwner;
CString m_strTableName;
CString m_strColumnName;
int m_nDataType;
CString m_strTypeName;
long m_lPrecision;
long m_lLength;
int m_nScale;
int m_nRadix;
int m_nNullable;
};
The code used in the .cpp file:
sFieldDef sTempField;
CColumns rsColumns(m_pDatabase);
rsColumns.Open(CRecordset::snapshot);
while( !rsColumns.IsEOF() )
{
sTempField.m_strQualifier=rsColumns.m_strQualifier;
sTempField.m_strOwner=rsColumns.m_strOwner;
sTempField.m_strTableName=rsColumns.m_strTableName;
sTempField.m_strColumnName=rsColumns.m_strColumnName;
sTempField.m_nDataType=rsColumns.m_nDataType;
sTempField.m_strTypeName=rsColumns.m_strTypeName;
sTempField.m_lPrecision=rsColumns.m_lPrecision;
sTempField.m_lLength=rsColumns.m_lLength;
sTempField.m_nScale=rsColumns.m_nScale;
sTempField.m_nRadix=rsColumns.m_nRadix;
sTempField.m_nNullable=rsColumns.m_nNullable;
pArrFiels->Add(sTempField);
rsColumns.MoveNext();
}

You seem to be copying and storing everything in an array of structs, where each struct has identical members with the corresponding record. Usually we use arrays through iterators. So why not provide an iterator to your record-set and avoid copying altogether? You could roughly start like this:
template <typename RS>
class rs_iterator
{
RS& rs;
public:
rs_iterator(RS& rs) : rs{rs} { }
const RS& operator*() { return rs; }
rs_iterator& operator++() { return rs.MoveNext(), *this; }
// ...
}
So you not only provide a convenient and standard interface to an array-like data source like a record-set, but you can use it directly in STL-like algorithms requiring bidirectional iterators.
If your CRecordset supports random access, then so would your iterator, easily. Otherwise, random access provision by itself is a good reason to copy (e.g. to sort columns).

Related

Is it is possible to construct container and filled data into it in one line using C++03?

Suppose I have a Container.
template<typename Type>
class Container
{
public:
Container(int size_)
{
size=size_;
data = new Type[size];
}
~Container()
{
delete [] data;
}
private:
int size;
Type* data;
};
I want construct the container and fill data into it in one line like this using C++03
// very easy to implement using C++11 std::initializer_list
Container<int> container{100,200,300}
or
Container<int> container(100,200,300)
or
// other one line solution
after do this, data[0]=100,data[1]=200,data[2]=300.
Thanks for your time.
Appendix
Similiar question is
How to fill data into container at once without temp variable in C++03
Evg already give the answer can implement a two lines solution.
Container<int> container(3);
container << 100, 200, 300;
I still wonder is there exist the one line solution?
The answer you link can almost do that. You only need a minor modification and that is: You need to make your container resizable. This is actually the major issue. Once you have that, adapting the solution is minor. Write a insert method that reallocates the memory and adjusts the size then only minor modifications on the proposed solution are necessary.
There is one caveat, and this is you cannot call the constructur call methods on the constructed object and assign it to a variable in the same line without a copy. For that it is possible to provide a conversion from Proxy to Container. I would rethink if putting something on a single line is really worth this cost, when it can be done much easier on two lines.
I didn't include the implementation of insert, because that would be sort of a different question:
#include <iostream>
template<typename Type>
class Container {
private:
struct Proxy {
Container* container;
Proxy(Container* container) : container(container) {}
Proxy& operator,(Type value) {
container->insert(value);
return *this;
}
operator Container() { return *container; }
};
public:
// ...
void insert(const Type& value) {
std::cout << value;
}
Proxy operator<<(Type value) {
insert(value);
return Proxy(this);
}
};
int main() {
Container<int> container = (Container<int>() << 1,2,3);
}
Output:
123
PS:
The problem is that, there is Container x={1,2,3,....,1000} everywhere in my project using C++11. Now, I must omove to C++03, and there is no std::itializer_list
Yes that is a problem. I suppose 1,2,3,...1000 is just an oversimplified example, otherwise you could use something similar to std::iota to fill the container (also only avaible since C++11, but not too difficult to implement). If that is the actual problem and you are looking for a temporary hack I would rather use plain arrays and construct the container from that:
int temp[] = {1,2,3,4,5 ....};
Container<int> x( &temp[0], &temp[999]);

Save reference to void pointer in a vector during loop iteration

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});
}
}

C++ unordered_map<string, ...> lookup without constructing string

I have C++ code that investigates a BIG string and matches lots of substrings. As much as possible, I avoid constructing std::strings, by encoding substrings like this:
char* buffer, size_t bufferSize
At some point, however, I'd like to look up a substring in one of these:
std::unordered_map<std::string, Info> stringToInfo = {...
So, to do that, I go:
stringToInfo.find(std::string(buffer, bufferSize))
That constructs a std::string for the sole purpose of the lookup.
I feel like there's an optimization I could do here, by... changing the key-type of the unordered_map to some kind of temporary string imposter, a class like this...
class SubString
{
char* buffer;
size_t bufferSize;
// ...
};
... that does the same logic as std::string to hash and compare, but then doesn't deallocate its buffer when it's destroyed.
So, my question is: is there a way to get the standard classes to do this, or do I write this class myself?
What you're wanting to do is called heterogeneous lookup. Since C++14 it's been supported for std::map::find and std::set::find (note versions (3) and (4) of the functions, which are templated on the lookup value type). It's more complicated for unordered containers because they need to be told of or find hash functions for all key types that will produce the same hash value for the same text. There's a proposal under consideration for a future Standard: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0919r0.html
Meanwhile, you could use another library that already supports heterogenous lookup, e.g. boost::unordered_map::find.
If you want to stick to std::unordered_map, you could avoid creating so many string temporaries by storing a std::string member alongside your unordered_map that you can reassign values to, then pass that string to find. You could encapsulate this in a custom container class.
Another route is to write a custom class to use as your unordered container key:
struct CharPtrOrString
{
const char* p_;
std::string s_;
explicit CharPtrOrString(const char* p) : p_{p} { }
CharPtrOrString(std::string s) : p_{nullptr}, s_{std::move(s)} { }
bool operator==(const CharPtrOrString& x) const
{
return p_ ? x.p_ ? std::strcmp(p_, x.p_) == 0
: p_ == x.s_
: x.p_ ? s_ == x.p_
: s_ == x.s_;
}
struct Hash
{
size_t operator()(const CharPtrOrString& x) const
{
std::string_view sv{x.p_ ? x.p_ : x.s_.c_str()};
return std::hash<std::string_view>()(sv);
}
};
};
You can then construct CharPtrOrString from std::strings for use in the unordered container keys, but construct one cheaply from your const char* each time you call find. Note that operator== above has to work out which you did (convention used is that if the pointer's nullptr then the std::string member's in use) so it compares the in-use members. The hash function has to make sure a std::string with a particular textual value will produce the same hash as a const char* (which it doesn't by default with GCC 7.3 and/or Clang 6 - I work with both and remember one had an issue but not which).
In C++20, you can now do this:
// struct is from "https://www.cppstories.com/2021/heterogeneous-access-cpp20/"
struct string_hash {
using is_transparent = void;
[[nodiscard]] size_t operator()(const char *txt) const {
return std::hash<std::string_view>{}(txt);
}
[[nodiscard]] size_t operator()(std::string_view txt) const {
return std::hash<std::string_view>{}(txt);
}
[[nodiscard]] size_t operator()(const std::string &txt) const {
return std::hash<std::string>{}(txt);
}
};
// Declaration of map
std::unordered_map<std::string, Info, string_hash, std::equal_to<>> map;
std::string_view key = "foo";
if (map.find(key))
{
// do something here
}
Just note that you will still need std::string when using []. There may be a way around that, but I'm not too sure

Is there a C++ container for unique values that supports strict size checking?

I'm looking for a C++ container to store pointers to objects which also meets the following requirements.
A container that keeps the order of elements (sequence container, so std::set is not suitable)
A container that has a member function which return the actual size (As std::array::size() always returns the fixed size, std::array is not suitable)
A container that supports random accesses such as operator [].
This is my code snippet and I'd like to remove the assertions used for checking size and uniqueness of elements.
#include <vector>
#include <set>
#include "assert.h"
class Foo {
public:
void DoSomething() {
}
};
int main() {
// a variable used to check whether a container is properly assigned
const uint8_t size_ = 2;
Foo foo1;
Foo foo2;
// Needs a kind of sequential containers to keep the order
// used std::vector instead of std::array to use member function size()
const std::vector<Foo*> vec = {
&foo1,
&foo2
};
std::set<Foo*> set_(vec.begin(), vec.end());
assert(vec.size() == size_); // size checking against pre-defined value
assert(vec.size() == set_.size()); // check for elements uniqueness
// Needs to access elements using [] operator
for (auto i = 0; i < size_; i++) {
vec[i]->DoSomething();
}
return 0;
}
Is there a C++ container which doesn't need two assertions used in my code snippet? Or should I need to make my own class which encapsulates one of STL containers?
So a class that acts like a vector except if you insert, it rejects duplicates like a set or a map.
One option might be the Boost.Bimap with indices of T* and sequence_index.
Your vector-like indexing would be via the sequence_index. You might even be willing to live with holes in the sequence after an element is erased.
Sticking with STLyou could implement a bidirectional map using 2 maps, or the following uses a map and a vector:
Note that by inheriting from vector I get all the vector methods for free, but I also risk the user downcasting to the vector.
One way round that without remodelling with a wrapper (a la queue vs list) is to make it protected inheritance and then explicitly using all the methods back to public. This is actually safer as it ensures you haven't inadvertently left some vector modification method live that would take the two containers out of step.
Note also that you would need to roll your own initializer_list constructor if you wanted one to filter out any duplicates. And you would have to do a bit of work to get this thread-safe.
template <class T>
class uniqvec : public std::vector<T*>
{
private:
typedef typename std::vector<T*> Base;
enum {push_back, pop_back, emplace_back, emplace}; //add anything else you don't like from vector
std::map <T*, size_t> uniquifier;
public:
std::pair<typename Base::iterator, bool> insert(T* t)
{
auto rv1 = uniquifier.insert(std::make_pair(t, Base::size()));
if (rv1.second)
{
Base::push_back(t);
}
return std::make_pair(Base::begin()+rv1.first.second, rv1.second);
}
void erase(T* t)
{
auto found = uniquifier.find(t);
if (found != uniquifier.end())
{
auto index = found->second;
uniquifier.erase(found);
Base::erase(Base::begin()+index);
for (auto& u : uniquifier)
if (u.second > index)
u.second--;
}
}
// Note that c++11 returns the next safe iterator,
// but I don't know if that should be in vector order or set order.
void erase(typename Base::iterator i)
{
return erase(*i);
}
};
As others have mentioned, your particular questions seems like the XY problem (you are down in the weeds about a particular solution instead of focusing on the original problem). There was an extremely useful flowchart provided here a number of years ago (credit to #MikaelPersson) that will help you choose a particular STL container to best fit your needs. You can find the original question here In which scenario do I use a particular STL container?.

How can I build iterator for object that I have created in C++

I want to build a simple iterator, for example - in the class: "myVector":
#include <iostream>
using namespace std;
#define maxSize 10
class myVector {
private:
int *arr;
int sp;
public:
myVector() {
arr = new int[maxSize];
sp = 0;
}
bool add(int num) {
if (sp==maxSize) return 0;
arr[sp] = num;
sp++;
return 1;
}
};
in the Example - I built a class that produces objects of type myVector. Now I want to build iterator with an operator ++ to run on the private Array of the vector.
thank you very much
You must support std::iterator_traits<YourIterator>. The easy way is to inherit from std::iterator<?> with the appropiate arguments.
In doing so you have to decide on an iterator category. This determines what you guarantee to support, both operator wise and behaviour wise.
Now, boost has some helper types to make writing an iterator a tad easier. Consider using boost. But a basic iterator is not impossible to write without them.
In the particular case above, a pointer is a valid iterator for your problem. And easier than either of the above options. Use this as your first iteration: KISS. Note that pointers have std::iterator_traits support for free.
To make your object iterable (and support for(auto&&x:c) syntax), either write a free begin and end function in the same namespace as your class that produces iterators, or add begin() and end() methods that do the same. I tend to also add size and empty and front and back as I find them useful. As an example:
T& back(){return *std::prev(end());}
T const& back()const{return *std::prev(end());}
You need to write something like this.
class myVector {
class myIterator {
private:
int *position; //operator ++ increment this position
public:
myIterator operator++(){
//increment position here
}
int& operator*(){
//return *pos
}
bool operator==(const myIterator &it)const {
//check that pos and it.pos are the same
}
};
};
This will work but wont be a STL compliant iterator, for that you will also need to add several typedefs, to say for instance the type of your iterator (in your case you have an input iterator). If you want an STL iterator the easiest thing is to use boost facade iterator.