After reading a number of questions on here such as Why doesn't QList have a resize() method?, I am wondering about the following.
Normally, in STL code I could have something like this to limit the size of results processed:
std::list<int> results = something()
results.resize(std::min(result.size(), 5000));
Now I have a Qt project with a QList:
QList<int> results = something()
while(results.size() > 5000) {
results.removeLast();
}
expensiveOperation(results);
Is this really the best way to to this with Qt containers a QList?
The reason is that I need to pass this eventually to a framework function expecting a QList.
QList != std::list. There's QLinkedList which is more like the std. version. For most operations QVector is preferred over QList as the container type to use in Qt. Read https://marcmutz.wordpress.com/effective-qt/containers/ for a full explanation.
If you're stuck with QList for some reason... then yeah... :( It may be quicker to get a new list with QList::mid(). And there's always QList::toVector() or toStdList(). :)
How about:
template<typename T>
static void truncate(QList<T> &list, int length) {
if (0 <= length && length < list.length()) {
list.erase(list.begin() + length, list.end());
}
}
Related
a is set< int> ARRAY, I want to copy it to b. BUT...
int main(){
set<int> a[10];
a[1].insert(99);
a[3].insert(99);
if(a[1]==a[3])cout<<"echo"<<endl;
set<int> b[10];
memcpy(b,a,sizeof(a));
if(b[1]==b[3])cout<<"echo"<<endl;// latch up here, what happen?
return 0;}
Do you know What is computer doing?
I assume the 'set' class you are using is a std::set? What makes you think that simplying memcpying the raw bytes of a std::set (or array of them, in this case) will work properly? This is highly dependent on the internal structure and implementation of the set class, and trying to do such a thing with anything more complicated than a primitive or array of primitives is almost guaranteed to give unexpected results. Doing this sort of raw byte manipulation when classes are involved is rarely going to be correct.
To do this properly you should iterate over the sets and use their '=' operator to assign them, which knows how to copy the contents properly:
for(int i = 0; i < 10; ++i) {
b[i] = a[i];
}
Even better you can use std::copy:
std::copy(std::begin(a), std::end(a), std::begin(b));
I am fairly new to Qt. It is the first framework I have worked with. I am writing a blackjack game using Qt. It seems to me that I should store the images of each card in a container class such as QVector. The container type would be of QImage. So I would have a declaration such as QVector<QImage> cards; Perhaps this is not the best way about approaching this problem so any alternative suggestion is of course welcomed. However, regardless, I would like to know if it is possible to initialize the container during the declaration. I have not been able to solve this so my solution is the following:
// Deck.h
class Deck
{
public:
Deck();
void shuffle(); // Creates new deck and shuffles it.
QImage &popCard(); // Removes first card off deck.
private:
void emptyDeck(); // Empty the deck so new cards can be added
QVector<QImage> cards;
QQueue<QImage> deck;
};
// Deck.cpp
Deck::Deck()
{
cards.push_back(QImage(":/PlayingCards/Clubs 1.png"));
cards.push_back(QImage(":/PlayingCards/Clubs 2.png"));
cards.push_back(QImage(":/PlayingCards/Clubs 3.png"));
cards.push_back(QImage(":/PlayingCards/Clubs 4.png"));
// continue process for entire deck of cards...
}
This seems to be painfully tedious especially if I consider adding a different style of playing cards later on, or if I give the user an option to change the style of the cards at run time. What would be an efficient design to this?
I would like to know if it is possible to initialize the container during the declaration
Yes you can since C++11:
QList<int> list{1, 2, 3, 4, 5};
Well about your question one of the way can be:
Create in resources all types of your images style calling like template, for example: "Name n.png", where n - number from 1 to 54 (cnt of cards with Jokers);
Create some QList<QImage> (I think it'll be better then QVector);
Create some QMap for searching correct template easy;
Create some enum class for template map;
Write a function that change images of your cards by selected enum.
However it is very light codding. I think there is more usefull ways and there is a lot of other more beauty ways to do this game and logic. But as part of your question here some code (can be not very right, cause write as is):
// Somewhere in global
enum class CardsTemplate: {
Clubs,
SomeTemp1,
SomeTemp2,
...
SomeTempN
}
.H file:
private:
QList<QImage> _images;
QMap<CardsTemplate, QString> _imagesMap {
{CardsTemplate::Clubs, QString("Clubs")},
{CardsTemplate::SomeTemp1, QString("SomeTemp1")},
{CardsTemplate::SomeTemp2, QString("SomeTemp2")},
...
{CardsTemplate::SomeTempN, QString("SomeTempN")}
}
public:
Deck(CardsTemplate temp);
void setNewTemplate(CardsTemplate temp);
.CPP file:
Deck::Deck(CardsTemplate temp){
for(int i = 1; i <= 54; i++)
_images << QImage(QString(":/Playing cards/%1 %2.png")
.arg(_imagesMap.value(temp)).arg(i));
}
void Deck::setNewTemplate(CardsTemplate temp) {
for(int i = 1; i <= _images.size(); i++)
_images[i] = QImage(QString(":/Playing cards/%1 %2.png")
.arg(_imagesMap.value(temp)).arg(i));
}
I am doing one project in which I define a data types like below
typedef QVector<double> QFilterDataMap1D;
typedef QMap<double, QFilterDataMap1D> QFilterDataMap2D;
Then there is one class with the name of mono_data in which i have define this variable
QFilterMap2D valid_filters;
mono_data Scan_data // Class
Now i am reading one variable from a .mat file and trying to save it in to above "valid_filters" QMap.
Qt Code: Switch view
for(int i=0;i<1;i++)
{
for(int j=0;j<1;j++)
{
Scan_Data.valid_filters[i][j]=valid_filters[i][j];
printf("\nValid_filters=%f",Scan_Data.valid_filters[i][j]);
}
}
The transferring is done successfully but then it gives run-time error
Windows has triggered a breakpoint in SpectralDataCollector.exe.
This may be due to a corruption of the heap, and indicates a bug in
SpectralDataCollector.exe or any of the DLLs it has loaded.
The output window may have more diagnostic information
Can anyone help in solving this problem. It will be of great help to me.
Thanks
Different issues here:
1. Using double as key type for a QMap
Using a QMap<double, Foo> is a very bad idea. the reason is that this is a container that let you access a Foo given a double. For instance:
map[0.45] = foo1;
map[15.74] = foo2;
This is problematic, because then, to retrieve the data contained in map[key], you have to test if key is either equal, smaller or greater than other keys in the maps. In your case, the key is a double, and testing if two doubles are equals is not a "safe" operation.
2. Using an int as key while you defined it was double
Here:
Scan_Data.valid_filters[i][j]=valid_filters[i][j];
i is an integer, and you said it should be a double.
3. Your loop only test for (i,j) = (0,0)
Are you aware that
for(int i=0;i<1;i++)
{
for(int j=0;j<1;j++)
{
Scan_Data.valid_filters[i][j]=valid_filters[i][j];
printf("\nValid_filters=%f",Scan_Data.valid_filters[i][j]);
}
}
is equivalent to:
Scan_Data.valid_filters[0][0]=valid_filters[0][0];
printf("\nValid_filters=%f",Scan_Data.valid_filters[0][0]);
?
4. Accessing a vector with operator[] is not safe
When you do:
Scan_Data.valid_filters[i][j]
You in fact do:
QFilterDataMap1D & v = Scan_Data.valid_filters[i]; // call QMap::operator[](double)
double d = v[j]; // call QVector::operator[](int)
The first one is safe, and create the entry if it doesn't exist. The second one is not safe, the jth element in you vector must already exist otherwise it would crash.
Solution
It seems you in fact want a 2D array of double (i.e., a matrix). To do this, use:
typedef QVector<double> QFilterDataMap1D;
typedef QVector<QFilterDataMap1D> QFilterDataMap2D;
Then, when you want to transfer one in another, simply use:
Scan_Data.valid_filters = valid_filters;
Or if you want to do it yourself:
Scan_Data.valid_filters.clear();
for(int i=0;i<n;i++)
{
Scan_Data.valid_filters << QFilterDataMap1D();
for(int j=0;j<m;j++)
{
Scan_Data.valid_filters[i] << valid_filters[i][j];
printf("\nValid_filters=%f",Scan_Data.valid_filters[i][j]);
}
}
If you want a 3D matrix, you would use:
typedef QVector<QFilterDataMap2D> QFilterDataMap3D;
I'm using a project which uses the Eigen library. I've had to already fixed an issue where when using the data types provided by eigen within a STL, I get an align error
error C2719: '_Val': formal parameter with __declspec(align('16'))
won't be aligned
see
http://eigen.tuxfamily.org/dox/TopicStlContainers.html or -http://www.mrpt.org/Matrices_vectors_arrays_and_Linear_Algebra_MRPT_and_Eigen_classes)
Once this was fixed i could compile and run.
But now at run time I'm getting another error
Debug Error!
R6010
abort() has been called.
So the code in question references my structure and a vector of my structure (with the eigen specially aligned fix):
typedef struct {
Vector4f v4;
Matrix4f M4;
bool b;
} my_struct;
typedef std::vector<my_struct, Eigen::aligned_allocator<my_struct>> my_struct;
Then my code fails after a when I try to create a new my_struct after a certain number of iterations (it can sometimes creates the new object, with no problems), other times it fails.
for (int i = 0; i<len; i++) {
Vector4f vec;
Matrix4f mat;
my_struct* temp = new my_struct();
}
Any ideas?
Tom
Without -DNDEBUG, you should have got an assert sending you to this page. In your case, you should follow this one. In short, add EIGEN_MAKE_ALIGNED_OPERATOR_NEW to your structure such that new my_struct call an aligned memory allocator.
I dont know a lot about C++, but I have to make work some C++ code with .NET. I try with DLLImport but I failed. So I try with C++/CLI to make kind of a wrapper.
But I'm not sure to understand everything...
This is the basic C++ H file with the function I want to export (MyFunction)
extern "C"
{
__declspec(dllexport) IplImage* MyFunction(IplImage *src, std::string* name, OneEnumerationType myEnum, bool myBool, float myFloat);
}
This is the Wrapper h code.
#include "MyFunction.h"; // the file containing the h code
#include <string>
namespace MyWrapper{
public ref class MyWrapperClass {
public:
MyWrapper(){};
IplImage^ GetMyFunction(IplImage *src, std::string^ name, OneEnumerationType myEnum, bool myBool, float myFloat);
}
This is the Wrapper cpp code.
#include "MyWrapperCode.h";
namespace MyWrapper{
IplImage^ MyWrapperClass::GetMyFunction(IplImage* src, std:string^ name, OneEnumerationType myEnum, bool myBool, float myFloat){
MyFunction(src, name, myEnum, myBool, myFloat);
}
}
These are my questions :
1) When I'm compiling, the error is "'^ : cannot use this indirection on type IplImage' and same message for type "std::string".
I have followed this logical :
ClasseNative clNat2 = *clNat; --> ClasseManagee clMan2 = *clMan;
ClasseNative &clNat3 = clNat2; --> ClasseManagee %clMan3 = clMan2;
ClasseNative *clNat4 = &clNat2; --> ClasseManagee ^clMan4 = %clMan2;
I have seen, that It was better to use System::String. I try this way but the initial function is using std::string... BTW, why is it better to change ?
2) How do I get the MyFunction IplImage result ? Thru a private member and a get I suppose but I dont know how to initialize it...
3) Tricky question. Is it possible for me to put the CLI obtains IplImage structure (from the OpenCV library) (the result of my function) inside a IplImage .NET structure, when I ll called my wrapper ? Dont know if the question is understandable...
Thanks a lot for your help.
Turning around for 3 days on this problem...
Your wrapper class needs to create a new std::string based on the content of a System::String^ parameter then pass to your native function. Otherwise you need to rewrite the function to take something else as the string input, for example a LPWSTR or LPCSTR.
You can write a ref class to have properties for all data that an IplImage would have, then pass that to your wrapper class. Your wrapper class then create an IplImage object based on the data of the ref class and pass to the native function. Reverse the data copying direction for the return value.
1) just by adding ^ you cannot change a native object to become managed, you have to create wrappers or transfer the data for example:
std::string nativeString = "my string";
String^ managedString = gcnew String(nativeString.c_str());
//now you can return it as
2) create a managed wrapper or use primitive datatype to transfer the data
3) note sure if this will help but look at Emgu.CV
try reading abit more about C++\CLI here are a few nice tutorials:
Quick C++/CLI - Learn C++/CLI in less than 10 minutes
C++/CLI for the C# programmer