I am learning more about smart pointers in C++14.
Consider the following MWC:
#include <iostream>
#include <string>
#include <memory>
class House {
public:
House &operator=(const House &house) = default;
House(const House &house) = default;
House(): id_habitants_(nullptr), num_habitants_() {}
explicit House(size_t num_habitants) {
if (num_habitants > 0) {
num_habitants_ = num_habitants;
id_habitants_ = new int[num_habitants_];
if (id_habitants_ != nullptr) {
for (size_t id = 0; id < num_habitants_; ++id) {
id_habitants_[id] = 1;
}
}
}
}
void Print() {
if (id_habitants_ != nullptr) {
for (size_t id = 0; id < num_habitants_; ++id) {
std::cout << id_habitants_[id] << ' ';
}
std::cout << std::endl;
} else {
std::cout << "<empty>" << std::endl;
}
}
~House() {
if (id_habitants_ != nullptr) {
delete [] id_habitants_;
}
num_habitants_ = 0;
}
private:
int *id_habitants_;
size_t num_habitants_;
};
int main() {
std::cout << "Testing unique_ptr.\n" << std::endl;
std::cout << "Using a dumb House class..." << std::endl;
std::cout << "Creating House h1 with 3 habitants..." << std::endl;
House h1(3);
std::cout << "IDs of h1's 3 habitants:" << std::endl;
h1.Print();
std::cout << "Creating House h2 with 0 habitants..." << std::endl;
House h2;
std::cout << "IDs of h2's 0 habitants:" << std::endl;
h2.Print();
std::cout << "Default-assigning h1 to h2..." << std::endl;
h2 = h1;
std::cout << "IDs of h2's new 3 habitants:" << std::endl;
h2.Print();
std::cout << "Destroying h1..." << std::endl;
h1.~House();
std::cout << "IDs of h2's new 3 habitants:" << std::endl;
h2.Print();
}
Without modifying the default copy constructor and the default assignment operator for the class House, how can I ensure correct pointer behavior during assignment via smart pointers?
On a first try it seems like using std::unique_ptr would be the way to go. I could create a new class:
class SmartHouse {
public:
SmartHouse &operator=(const SmartHouse &shouse) = default;
SmartHouse(const SmartHouse &shouse) = default;
SmartHouse(): id_habitants_(nullptr), num_habitants_() {}
explicit SmartHouse(size_t num_habitants) {
if (num_habitants > 0) {
num_habitants_ = num_habitants;
id_habitants_ = std::unique_ptr<int[]>(new int[num_habitants_]);
if (id_habitants_) {
for (size_t id = 0; id < num_habitants_; ++id) {
id_habitants_[id] = 1;
}
}
}
}
void Print() {
if (id_habitants_) {
for (size_t id = 0; id < num_habitants_; ++id) {
std::cout << id_habitants_[id] << ' ';
}
std::cout << std::endl;
} else {
std::cout << "<empty>" << std::endl;
}
}
~SmartHouse() {
num_habitants_ = 0;
}
private:
std::unique_ptr<int[]> id_habitants_;
size_t num_habitants_;
};
According to this, I can't really copy one unique pointer to another. Makes sense, right? It sort of defeats the purpose of it being unique. I.e. this would not compile:
SmartHouse sh1(3);
SmartHouse sh2;
sh2 = sh1;
But I could specify a move assignment operator and have the unique_ptr<int[]> member be moved upon assignment thus transferring ownership of the pointed data to the left object upon assignment:
class SmartHouse {
SmartHouse &operator=(SmartHouse &&SmartHouse) = default;
}
...
SmartHouse sh1(3);
SmartHouse sh2;
sh2 = std::move(sh1);
sh1.~SmartHouse();
sh2.Print();
Core question: Does this make sense at all? Are there better ways to enhance assignment of pointer member variables?
Full MWE.
Related
Let the data structure be anything (Array, Vectors, Std::Variant). But what is the difference in traversing using just for/for_each against std::visit.
for (auto& Element: collection){
std::visit([](auto arg){std::cout << arg << " ";}, Element);
}
And
for_each(collection.begin(), collection.end(), [](Element& e)
{
std::cout << e;
});
Note1: I know C-style for loop vs C++ for_each..For_each avoids typo error/syntactic sugar. so we can be happy with just for_each.
Note2: I know visitor design pattern too, which will be used for polymorphic object against polymorphic behaviour.
But still I couldn't appreciate and understand std::visit.
And when I digged further, I came to know something called Overload pattern.
template<typename ... Ts>
struct Overload : Ts ... {
using Ts::operator() ...;
};
template<class... Ts> Overload(Ts...) -> Overload<Ts...>;
But this Overload pattern too can be done using the same for_each right?
Thanks in advance for the reply.,
The difference between your first and second method is that the second does not work if your collection elements are variants. The example below compiles and lists your options.
Methods 2 and 4 are the only elegant ones I believe. But Method 2 is limited (see how it prints) while Method 4 gives you all the flexibility you may wish for.
But this does not necessarily mean Method 4 is the way to go. Place some intentional errors in Method 4 and then look at the error messages. They are mostly unintelligible.
#include <iostream>
#include <utility>
#include <variant>
#include <vector>
#include <algorithm>
using Element = std::variant<int, std::string>;
using Collection = std::vector<Element>;
Collection c = {1, 2, "three", "four", 5};
auto print_int = [](int const & e)
{
std::cout << "int: " << e << std::endl;
};
auto print_str = [](std::string const & e)
{
std::cout << "string: " << e << std::endl;
};
auto print_any = [](auto && e)
{
std::cout << "element: " << e << std::endl;
};
void Method1 ()
{
for (Element const & e: c)
{
{
auto const * i = std::get_if<int>(&e);
if (i)
{
print_int(*i);
continue;
}
}
{
auto const * s = std::get_if<std::string>(&e);
if (s)
{
print_str(*s);
continue;
}
}
}
}
void Method2 ()
{
for (Element const & e: c)
{
std::visit(print_any, e);
}
}
void Method3 ()
{
std::for_each(c.cbegin(), c.cend(), [](Element const & e)
{
std::visit(print_any, e);
});
}
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
void Method4 ()
{
for (Element const & e: c)
{
std::visit(overloaded
{
[](int i) { print_int(i); },
[](std::string s) { print_str(s) ; }
}, e);
}
}
int main ()
{
std::cout << std::endl << "Method1" << std::endl;
Method1();
std::cout << std::endl << "Method2" << std::endl;
Method2();
std::cout << std::endl << "Method3" << std::endl;
Method3();
std::cout << std::endl << "Method4" << std::endl;
Method4();
}
I tried to implement an automation tool, and got problem when intercepting IME (Windows 10's default Microsoft IME) input Unicode strings (such as Japanese/Chinese).
I've written a 64-bit dll for injection to other processes/windows. The dll is as follows,
#include <windows.h>
#include <fstream>
#include <locale>
// for output only
static wchar_t* className(HWND hwnd) {
static wchar_t className[128];
::GetClassNameW(hwnd, className, 128);
return className;
}
extern "C" __declspec(dllexport) LRESULT CALLBACK ImeCallback(int code, WPARAM wParam, LPARAM lParam) {
std::wofstream out("test.log", std::ios::app);
out.imbue(std::locale("zh_CN.UTF-8"));
if (code >= 0)
{
PCWPSTRUCT msg = (PCWPSTRUCT)lParam;
if (msg->message == WM_IME_COMPOSITION) {
out << "composition: " << className(msg->hwnd) << ":";
if (msg->lParam & GCS_COMPATTR) {
out << ":GCS_COMPATTR";
}
if (msg->lParam & GCS_COMPCLAUSE) {
out << ":GCS_COMPCLAUSE";
}
if (msg->lParam & GCS_COMPREADSTR) {
out << ":GCS_COMPREADSTR";
}
if (msg->lParam & GCS_COMPREADATTR) {
out << ":GCS_COMPREADATTR";
}
if (msg->lParam & GCS_COMPREADCLAUSE) {
out << ":GCS_COMPREADCLAUSE";
}
if (msg->lParam & GCS_COMPSTR) {
out << ":GCS_COMPSTR";
}
if (msg->lParam & GCS_CURSORPOS) {
out << ":GCS_CURSORPOS";
}
if (msg->lParam & GCS_DELTASTART) {
out << ":GCS_DELTASTART";
}
if (msg->lParam & GCS_RESULTCLAUSE) {
out << ":GCS_RESULTCLAUSE";
}
if (msg->lParam & GCS_RESULTREADCLAUSE) {
out << ":GCS_RESULTREADCLAUSE";
}
if (msg->lParam & GCS_RESULTREADSTR) {
out << ":GCS_RESULTREADSTR";
}
if (msg->lParam & GCS_RESULTSTR) {
out << ":GCS_RESULTSTR";
}
out << std::endl;
if (msg->lParam & GCS_RESULTSTR) {
wchar_t data[128] = { 0 };
HIMC context = ImmGetContext(msg->hwnd);
ImmGetCompositionStringW(context, GCS_RESULTSTR, data, 255);
ImmReleaseContext(msg->hwnd, context);
out << " result data: " << data << std::endl;
}
else if (msg->lParam & GCS_COMPSTR) {
wchar_t data[128] = { 0 };
HIMC context = ImmGetContext(msg->hwnd);
ImmGetCompositionStringW(context, GCS_COMPSTR, data, 255);
ImmReleaseContext(msg->hwnd, context);
out << " composition data: " << data << std::endl;
}
}
else if (msg->message == WM_IME_STARTCOMPOSITION) {
out << "start composition" << std::endl;
}
else if (msg->message == WM_IME_ENDCOMPOSITION)
{
out << "end composition" << std::endl;
}
else if (msg->message == WM_IME_SETCONTEXT) {
out << "set context : " << className(msg->hwnd) << ":" << (wParam ? "TRUE" : "FALSE") << std::endl;
switch (msg->lParam) {
case ISC_SHOWUICOMPOSITIONWINDOW:
out << " ISC_SHOWUICOMPOSITIONWINDOW" << std::endl;
break;
case ISC_SHOWUIGUIDELINE:
out << " ISC_SHOWUIGUIDELINE" << std::endl;
break;
case ISC_SHOWUIALLCANDIDATEWINDOW:
out << " ISC_SHOWUIALLCANDIDATEWINDOW" << std::endl;
break;
case ISC_SHOWUIALL:
out << " ISC_SHOWUIALL" << std::endl;
break;
case ISC_SHOWUICANDIDATEWINDOW:
out << " ISC_SHOWUICANDIDATEWINDOW" << std::endl;
break;
case ISC_SHOWUICANDIDATEWINDOW << 1:
out << " ISC_SHOWUICANDIDATEWINDOW << 1" << std::endl;
break;
case ISC_SHOWUICANDIDATEWINDOW << 2:
out << " ISC_SHOWUICANDIDATEWINDOW << 2" << std::endl;
break;
case ISC_SHOWUICANDIDATEWINDOW << 3:
out << " ISC_SHOWUICANDIDATEWINDOW << 3" << std::endl;
break;
default:
out << " default" << std::endl;
}
}
else if (msg->message == WM_IME_NOTIFY) {
HIMC context;
wchar_t data[128] = { 0 };
out << "notify : " << className(msg->hwnd) << std::endl;
switch (msg->wParam) {
case IMN_CHANGECANDIDATE:
out << " IMN_CHANGECANDIDATE" << std::endl;
break;
case IMN_CLOSECANDIDATE:
out << " IMN_CLOSECANDIDATE" << std::endl;
break;
case IMN_CLOSESTATUSWINDOW:
out << " IMN_CLOSESTATUSWINDOW" << std::endl;
break;
case IMN_GUIDELINE:
out << " IMN_GUIDELINE" << std::endl;
break;
case IMN_OPENCANDIDATE:
out << " IMN_OPENCANDIDATE" << std::endl;
break;
case IMN_OPENSTATUSWINDOW:
out << " IMN_OPENSTATUSWINDOW" << std::endl;
break;
case IMN_SETCANDIDATEPOS:
out << " IMN_SETCANDIDATEPOS" << std::endl;
break;
case IMN_SETCOMPOSITIONFONT:
out << " IMN_SETCOMPOSITIONFONT" << std::endl;
break;
case IMN_SETCOMPOSITIONWINDOW:
out << " IMN_SETCOMPOSITIONWINDOW" << std::endl;
break;
case IMN_SETCONVERSIONMODE:
out << " IMN_SETCONVERSIONMODE" << std::endl;
break;
case IMN_SETOPENSTATUS:
out << " IMN_SETOPENSTATUS" << std::endl;
break;
case IMN_SETSENTENCEMODE:
out << " IMN_SETSENTENCEMODE" << std::endl;
break;
case IMN_SETSTATUSWINDOWPOS:
out << " IMN_SETSTATUSWINDOWPOS" << std::endl;
break;
default:
out << " default: " << msg->wParam << ":" << msg->lParam << std::endl;
context = ImmGetContext(msg->hwnd);
auto result = ImmGetCompositionStringW(context, GCS_RESULTSTR, data, 256);
ImmReleaseContext(msg->hwnd, context);
out << " data: " << data << std::endl;
}
}
else if (msg->message == WM_IME_CHAR) {
out << "char:" << msg->wParam << std::endl;
}
else if (msg->message == WM_IME_CONTROL) {
out << "control" << std::endl;
}
else if (msg->message == WM_IME_SELECT) {
out << "select : " << className(msg->hwnd) << " : " << (msg->wParam ? "TRUE" : "FALSE") << " : " << msg->lParam << std::endl;
}
else if (msg->message == WM_IME_KEYDOWN) {
out << "key down" << std::endl;
}
else if (msg->message == WM_IME_KEYUP) {
out << "key up" << std::endl;
}
else if (msg->message == WM_IME_REQUEST) {
out << "request" << std::endl;
}
}
out.close();
return ::CallNextHookEx(0, code, wParam, lParam);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
I then wrote a 64-bit .NET application to inject this dll.
public delegate long HookProc(long code, long wParam, long lParam);
[DllImport("kernel32.dll", EntryPoint = "LoadLibraryW", SetLastError = true)]
public static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPWStr)] string lpFileName);
[DllImport("kernel32.dll", EntryPoint = "FreeLibrary", SetLastError = true)]
public static extern IntPtr FreeLibrary([In] IntPtr hModule);
[DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true, ThrowOnUnmappableChar = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName);
[DllImport("user32.dll")]
public static extern int SetWindowsHookEx(int hookType, HookProc hookFn, IntPtr hMod, int threadId);
[DllImport("user32.dll")]
public static extern int UnhookWindowsHookEx(int hookId);
public int hookId;
private void button1_Click(object sender, EventArgs e)
{
IntPtr hMod = LoadLibrary("ImeHook.dll");
IntPtr callback = GetProcAddress(hMod, "ImeCallback");
// 4 represents WH_CALLWNDPROC
// Try to inject into all other 64-bits applications
hookId = SetWindowsHookEx(4, (HookProc)Marshal.GetDelegateForFunctionPointer(callback, typeof(HookProc)), hMod, 0);
}
private void button2_Click(object sender, EventArgs e)
{
UnhookWindowsHookEx(hookId);
}
The program can indeed inject the DLL into other processes because I can see messages from various windows in the logging file.
I can even intercept the IME Unicode strings in the WM_IME_COMPOSITION message (GCS_RESULTSTR), but only for some applications such as 64-bit forms written by .NET.
For some other applications, such as Firefox and Microsoft Edge, I can only see some WM_IME_NOTIFY messages, and there are no any WM_IME_COMPOSITION/WM_IME_STARTCOMPOSITION/WM_IME_ENDCOMPOSITION messages received for these windows. Therefore I cannot get the final Unicode input strings for these windows.
Did I do something wrong? Is it even possible to get such information for all processes or windows (such as 64-bit Edge/Chrome/Firefox) in Windows 10?
I also tried the method you described in this question but failed to capture the windows IME output Unicode string(Chinese)
I found something from the Microsoft docs site, after windows XP, windows introduce the Text Services Framework, and the TSF manager functions as a mediator between an application and one or more text services, maybe there is no message like WM_IME_COMPOSITION or WM_CHAR sent by the IME for Firefox/Chrome/World in latest OS(windows 10 or 11)
but when I use Notepad, still can get the Unicode string of Chinese by hook WH_CALLWNDPROC
I have to implement a deck of cards with a number and a letter. This is what I have done so far:
string deck [6][6] =
{
{1A, 1B, 1C, 1D},
{2A, 2B, 2C, 2D},
{3A, 3B, 3C, 3D},
{4A, 4B, 4C, 4D},
{ , , , };
};
int main ()
{
cout << deck[0][0] << endl;
}
I get an error:
invalid suffix 'A' on integer constant
You are getting this error because you need to wrap your strings in double quotations. If you want to use a static initialization/declaration, it should look something like this:
std::string deck[4][4] = {
{ "1A", "1B", "1C", "1D"},
{ "2A", "2B", "2C", "2D"},
{ "3A", "3B", "3C", "3D"},
{ "4A", "4B", "4C", "4D"}
};
You can display the entire contents of the deck by using two nested for loops:
for (int r=0; r < 4; ++r) {
for (int c=0; c < 4; ++c) {
if (c > 0) {
cout << " ";
}
cout << deck[r][c];
}
cout << "\n";
}
I have a two dimensional float array in QML. How do I get its values in C++.
I have created a class in c++ and have done the part of qmlRegisterType. The class is now accessible in QML.
Please demonstrate with a small example.
Here's what I have tried:
Header:
#include <QQuickItem>
#include <iostream>
class Controller : public QObject
{
Q_OBJECT
Q_PROPERTY(QList <QVariantList> names READ names WRITE setnames NOTIFY namesChanged)
QList <QVariantList> m_names;
public:
Controller()
{
}
~Controller() {
}
QList <QVariantList> names() const
{
return m_names;
}
public slots:
void setnames(QList <QVariantList> arg)
{
QVariantList p;
if (arg.size () > 0)
{
p = arg.first ();
std::cout << "\narg: \n" << p[0].toInt ();
}
else
std::cout << "\nqqqq " << arg.size () << "\n";
}
signals:
void namesChanged(QList <QVariantList> arg);
};
qml
import QtQuick 2.0
import FromCpp 1.0
Rectangle
{
property variant arras: [[1,2,3], [4,5,6]]
Controller
{
id: ppp
}
MouseArea
{
anchors.fill: parent
onClicked:
{
ppp.setnames(arras)
console.log(arras.length)
}
}
}
The exact output from QtCreator:
Starting /home/***/documents/test/build-junk-Desktop_Qt_5_1_0_GCC_64bit-Debug/junk...
QML debugging is enabled. Only use this in a safe environment.
2
qqqq 0
QThreadStorage: Thread 0x181e270 exited after QThreadStorage 2 destroyed
/home/***/documents/test/build-junk-Desktop_Qt_5_1_0_GCC_64bit-Debug/junk exited with code 0
///
Here, as you can see the size of the 2D array from QML is printed correctly as 2 and the size is printed 0 from c++.
Why is that happening? Please explain.
According to user1095108's answer, in order to access the internal elements of the QML's 2 Dim array passed to C++, we need to convert each row to a list as follows:
QML part:
import QtQuick 2.0
import FromCpp 1.0
Rectangle
{
property variant twoDimArray: [[1,2,3], [4,5,6]]
Controller
{
id: controllerA
}
MouseArea
{
anchors.fill: parent
onClicked:
{
controllerA.setname (twoDimArray)
}
}
}
C++ part:
void setname (QVariantList arg)
{
if (arg.size())
{
QList <QVariant> p = arg[0].toList();
std::cout << "\nRow0 0:" << p[0].toInt ();
std::cout << "\nRow0 1:" << p[1].toInt ();
std::cout << "\nRow0 2:" << p[2].toInt ();
std::cout << "\n";
QList <QVariant> p1 = arg[1].toList();
std::cout << "\nRow1 0:" << p1[0].toInt ();
std::cout << "\nRow1 1:" << p1[1].toInt ();
std::cout << "\nRow1 2:" << p1[2].toInt ();
}
}
Output:
Starting /home/.../documents/test/build-junk-Desktop_Qt_5_1_0_GCC_64bit-Debug/junk...
QML debugging is enabled. Only use this in a safe environment.
Row0 0:1
Row0 1:2
Row0 2:3
Row1 0:4
Row1 1:5
Row1 2:6/home/.../documents/test/build-junk-Desktop_Qt_5_1_0_GCC_64bit-Debug/junk exited with code 0
It is actually very simple. Javascript arrays map to QVariantLists, Javascript objects to QVariantMaps. Therefore, you are dealing with nested QVariantLists. Try this:
void setnames(QVariantList const& arg)
{
if (arg.size())
{
auto const p(arg.front().toList());
std::cout << "\narg: \n" << p.front().toInt();
}
else
std::cout << "\nqqqq " << arg.size () << "\n";
}
This is my method :
#include <QQuickItem>
#include <QDebug>
#include <QVariantList>
class Controller : public QObject
{
Q_OBJECT
Q_PROPERTY(QVariant names READ names WRITE setnames NOTIFY namesChanged)
QVariant m_names;
public:
Controller()
{
}
~Controller() {
}
QVariant names() const
{
return m_names;
}
public slots:
void setnames(QVariant arg)
{
QVariantList dim1 = arg.toList();
qDebug() << "outer dimension size" << dim1.size();
for(int i=0;i<dim1.size();++i)
{
QVariantList &dim2 = dim1.at(i).toList();
qDebug() << "inner dimension size at" << dim2.size();
}
}
signals:
void namesChanged();
};
Try this:
Somewhere in QML file:
property variant floats: [1.1, 2.2, 3.3, 4.4, 5.5, 6.6]
Includes:
#include <QtQuick/QQuickView>
#include <QQmlContext>
#include <QQmlProperty>
#include <QQuickItem>
In C++, in constructor for example:
QQuickView *view = new QQuickView();
QWidget *container = QWidget::createWindowContainer(view, ui->widget);//I show view in my widget
container->setMinimumSize(ui->widget->size());
container->setMaximumSize(ui->widget->size());
view->setSource(QUrl::fromLocalFile("pathToQMLFile"));
//starts here
QQmlProperty property(view->rootObject(), "floats");//get rootObject and set name of property
QVariantList lst = property.read().toList();//use raed method to get QVariant and convert it to list
for (int i = 0; i < lst.length(); ++i)
{
qDebug() << lst.at(i).toFloat();//show list
}
Output:
1.1
2.2
3.3
4.4
5.5
6.6
I hope my code shows main idea and you can use it in your class, because the most important job(how to get numbers) was done.
It looks like you can use QVariantList (or QList<QVariant>):
#include <QtQuick>
class Controller : public QObject
{
Q_OBJECT
Q_PROPERTY(QVariantList names READ names WRITE setnames NOTIFY namesChanged)
QVariantList m_names;
public:
Controller()
{
}
~Controller() {
}
QVariantList names() const
{
return m_names;
}
public slots:
void setnames(QVariantList arg)
{
qDebug() << arg;
}
signals:
void namesChanged(QVariantList arg);
};
#include <QApplication>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
qmlRegisterType<Controller>("FromCpp", 1, 0, "Controller");
QQuickView view(QUrl(QStringLiteral("main.qml")));
view.show();
return app.exec();
}
#include "main.moc"
Output:
(QVariant(QVariantList, (QVariant(int, 1) , QVariant(int, 2) , QVariant(int, 3) ) ) , QVariant(QVariantList, (QVariant(int, 4) , QVariant(int, 5) , QVariant(int, 6) ) ) )
Im constantly getting this when I build on Qtcreator.
*** glibc detected *** /home/Exxamples/EffectivCons: realloc(): invalid pointer: 0xb6fb5414 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x75ee2)[0xb6603ee2]
/lib/i386-linux-gnu/libc.so.6(realloc+0x25d)[0xb660856d]
/lib/i386-linux-gnu/libc.so.6(realloc+0x273)[0xb6608583]
/opt/Qt5.1.1/5.1.1/gcc/lib/libQt5Core.so.5(_ZN9QListData7reallocEi+0x37)[0xb6906e67]
/opt/Qt5.1.1/5.1.1/gcc/lib/libQt5Core.so.5(_ZN9QListData6appendEi+0x7c)[0xb6906f4c]
/opt/Qt5.1.1/5.1.1/gcc/lib/libQt5Core.so.5(_ZN9QListData6appendEv+0x23)[0xb6906fd3]
/opt/Qt5.1.1/5.1.1/gcc/lib/libQt5Core.so.5(+0x1afa3e)[0xb6a05a3e]
/opt/Qt5.1.1/5.1.1/gcc/lib/libQt5Core.so.5(_Z21qRegisterResourceDataiPKhS0_S0_+0x216)[
This is my code, through the other questions on the website, I saw some users using malloc or realloc, but Im not using it, why am i getting an error?
#include <termios.h>
#include <string.h>
#include <stdlib.h>
#define BUFLEN 512
std::string numberToString(const int n);
void sendExpressivAnimation(int,EmoStateHandle eState);
void handleExpressivEvent(std::ostream& os, EmoEngineEventHandle expressivEvent);
bool handleUserInput();
void promptUser();
void nonblocking();
int getch();
int kbhit();
int createSocket();
int startSendPort = 30000;
struct termios initial_settings, new_settings;
int kbhit (void)
{
struct timeval tv;
fd_set rdfs;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&rdfs);
FD_SET (STDIN_FILENO, &rdfs);
select(STDIN_FILENO+1, &rdfs, NULL, NULL, &tv);
return FD_ISSET(STDIN_FILENO, &rdfs);
}
int main(int argc, char **argv)
{
EmoEngineEventHandle eEvent = EE_EmoEngineEventCreate();
EmoStateHandle eState = EE_EmoStateCreate();
unsigned int userID = 0;
const int CONTROL_PANEL_PORT = 3008;
bool connected = false;
if(EE_EngineRemoteConnect("127.0.0.1", CONTROL_PANEL_PORT)== EDK_OK)
{
std::cout <<"Emotiv Engine started" << std::endl;
connected = true;
}
else
{
std::cout <<"Emotiv Engine failed !"<< std::endl;
connected = false;
}
std::cout << "Type \"exit\" to quit, \"help\" to list available commands..." << std::endl;
promptUser();
int _socket;
_socket = createSocket();
if(connected)
{
nonblocking();
fflush(stdin);
while (true) {
// Handle the user input
//if (_kbhit()) {
if (!handleUserInput()) {
break;
}
//}
int state = EE_EngineGetNextEvent(eEvent);
// New event needs to be handled
if (state == EDK_OK) {
EE_Event_t eventType = EE_EmoEngineEventGetType(eEvent);
EE_EmoEngineEventGetUserId(eEvent, &userID);
switch (eventType) {
// New headset connected, create a new socket to send the animation
case EE_UserAdded:
{
std::cout << std::endl << "New user " << userID << " added, sending Expressiv animation to ";
std::cout << "127.0.0.1" << ":" << startSendPort << "..." << std::endl;
promptUser();
break;
}
// Headset disconnected, remove the existing socket
case EE_UserRemoved:
{
std::cout << std::endl << "User " << userID << " has been removed." << std::endl;
promptUser();
break;
}
// Send the Expressiv animation if EmoState has been updated
case EE_EmoStateUpdated:
{
//std::cout << "New EmoState from user " << userID << "..." << std::endl;
EE_EmoEngineEventGetEmoState(eEvent, eState);
sendExpressivAnimation(_socket,eState);
break;
}
// Handle Expressiv training event
case EE_ExpressivEvent:
{
handleExpressivEvent(std::cout, eEvent);
break;
}
default:
break;
}
}
else if (state != EDK_NO_EVENT) {
std::cout << std::endl << "Internal error in Emotiv Engine!" << std::endl;
break;
}
}
}
EE_EngineDisconnect();
EE_EmoStateFree(eState);
EE_EmoEngineEventFree(eEvent);
return 0;
}
std::string numberToString(const int n) {
char* buf;
//_itoa(n, buf, 10);
QString nStr = QString::number(n);
buf = nStr.toLocal8Bit().data();
return std::string(buf);
}
void sendExpressivAnimation(int _socket,EmoStateHandle eState) {
std::ostringstream output;
EE_ExpressivAlgo_t upperFaceType = ES_ExpressivGetUpperFaceAction(eState);
EE_ExpressivAlgo_t lowerFaceType = ES_ExpressivGetLowerFaceAction(eState);
float upperFaceAmp = ES_ExpressivGetUpperFaceActionPower(eState);
float lowerFaceAmp = ES_ExpressivGetLowerFaceActionPower(eState);
if (ES_ExpressivIsBlink(eState)) {
output << "B,";
}
if (ES_ExpressivIsLeftWink(eState)) {
output << "l,";
}
if (ES_ExpressivIsRightWink(eState)) {
output << "r,";
}
if (ES_ExpressivIsLookingRight(eState)) {
output << "R,";
}
if (ES_ExpressivIsLookingLeft(eState)) {
output << "L,";
}
if (upperFaceAmp > 0.0) {
switch (upperFaceType) {
case EXP_EYEBROW: output << "b"; break;
case EXP_FURROW: output << "f"; break;
default: break;
}
output << numberToString(static_cast<int>(upperFaceAmp*100.0f)) << ",";
}
if (lowerFaceAmp > 0.0) {
switch (lowerFaceType) {
case EXP_CLENCH: output << "G"; break;
case EXP_SMILE: output << "S"; break;
case EXP_LAUGH: output << "H"; break;
case EXP_SMIRK_LEFT: output << "sl"; break;
case EXP_SMIRK_RIGHT: output << "sr"; break;
default: break;
}
output << numberToString(static_cast<int>(lowerFaceAmp*100.0f)) << ",";
}
std::string outString = output.str();
// Remove the last comma
if (outString.length()) {
outString.resize(outString.length()-1);
}
if (!outString.length()) {
outString = std::string("neutral");
}
if(send(_socket, outString.c_str(), BUFLEN, 0)==-1)
{
std::cout<<"sending error"<<std::endl;
//exit(1);
}
}
void handleExpressivEvent(std::ostream& os, EmoEngineEventHandle expressivEvent) {
unsigned int userID = 0;
EE_EmoEngineEventGetUserId(expressivEvent, &userID);
EE_ExpressivEvent_t eventType = EE_ExpressivEventGetType(expressivEvent);
switch (eventType) {
case EE_ExpressivTrainingStarted:
{
os << std::endl << "Expressiv training for user " << userID << " STARTED!" << std::endl;
break;
}
case EE_ExpressivTrainingSucceeded:
{
os << std::endl << "Expressiv training for user " << userID << " SUCCEEDED!" << std::endl;
break;
}
case EE_ExpressivTrainingFailed:
{
os << std::endl << "Expressiv training for user " << userID << " FAILED!" << std::endl;
break;
}
case EE_ExpressivTrainingCompleted:
{
os << std::endl << "Expressiv training for user " << userID << " COMPLETED!" << std::endl;
break;
}
case EE_ExpressivTrainingDataErased:
{
os << std::endl << "Expressiv training data for user " << userID << " ERASED!" << std::endl;
break;
}
case EE_ExpressivTrainingRejected:
{
os << std::endl << "Expressiv training for user " << userID << " REJECTED!" << std::endl;
break;
}
case EE_ExpressivTrainingReset:
{
os << std::endl << "Expressiv training for user " << userID << " RESET!" << std::endl;
break;
}
case EE_ExpressivNoEvent:
default:
//## unhandled case
assert(0);
return;
}
promptUser();
}
bool handleUserInput() {
static std::string inputBuffer;
char c = getch();
if ((int)c == 10) {
std::cout << std::endl;
std::string command;
const size_t len = inputBuffer.length();
command.reserve(len);
// Convert the input to lower case first
for (size_t i=0; i < len; i++) {
command.append(1, tolower(inputBuffer.at(i)));
}
inputBuffer.clear();
bool success = parseCommand(command, std::cout);
promptUser();
return success;
}
else {
if ((int)c == 127) { // Backspace key
if (inputBuffer.length()) {
putchar('\b');
putchar(' ');
putchar('\b');
inputBuffer.erase(inputBuffer.end()-1);
}
}
else {
std::cout << c;
if(((int) c == 32) || ((int)c == 95) || (((int)c >= 97 && (int)c <=122)) || (((int)c >=48 && (int)c <= 57)))
inputBuffer.append(1,c);
}
}
return true;
}
void promptUser()
{
std::cout << "ExpressivDemo> "<<std::endl;
}
void nonblocking()
{
tcgetattr(0, &initial_settings);
new_settings = initial_settings;
new_settings.c_lflag &= ~ICANON;
new_settings.c_lflag &= ~ECHO;
//new_settings.c_lflag &= ~ISIG;
new_settings.c_cc[VMIN] = 0;
new_settings.c_cc[VTIME] = 0;
tcsetattr(0, TCSANOW, &new_settings);
}
int getch()
{
int r;
unsigned char c=0;
if((r = read(0, &c, sizeof(c))) < 0 )
{
return r;
}
else
{
return c;
}
}
int createSocket()
{
struct sockaddr_in si_other;
int s, slen = sizeof(si_other);
if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
std::cout<<"socket"<<std::endl;
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(startSendPort);
if (inet_aton("127.0.0.1", &si_other.sin_addr)==0)
{
std::cout<<"intet_aton failed !"<<std::endl;
//exit(1);
}
if(connect(s,(sockaddr*)&si_other,slen)==-1)
{
std::cout<<"connect failed !"<<std::endl;
// exit(1);
}
return s;
}
Your code is too big to be checked wholly. If you can reduce it to a SSCCE it will be easier for everybody.
Anyway, skimming over your code, only one thing catched my eye:
char *buf;
QString nStr = QString::number(n);
buf = nStr.toLocal8Bit().data();
return std::string(buf);
The call to toLocal8Bit() returns a temporary QByteArray and then you call its data() member function. The returned pointer is only valid during the lifetime of that temporary, that is, until the ending ;. After that the buf pointer is invalid and the next line renders undefined behavior.
You should do something like:
QString nStr = QString::number(n);
QByteArray a(nStr.toLocal8Bit());
char *buf = a.data();
return std::string(buf);
Or even better:
QString nStr = QString::number(n);
return std::string(nStr.toLocal8Bit().data());
Or just for show:
return std::string(QString::number(n).toLocal8Bit().data());