shared_ptr vs. new operator: which one to use - c++

In the function below I have made use of http_client from cpprestsdk (https://github.com/Microsoft/cpprestsdk) to make http requests to a network camera. The function below is probably a callback called by the lcm library (http://lcm-proj.github.io/) when a certain request is made.
I had problems with line 11. I was previously using the new operator:
auto init_session_response = new init_session_response_t;
to create the pointer and manually delete it just before exiting the function.
But I got a access violation exception when trying to modify the init_session_response object in the pplx task continuation at line 49.
init_session_response->status_code =
ptz_camera::status_codes_t::OK;
This problem went away when I started using std::shared_ptr. Can someone explain to me why using shared_ptr solved the problem? Should the http_client* also be created using std::shared_ptr?
1 void lcm_handler::on_init_session_req(const lcm::ReceiveBuffer* rbuff,
2 const std::string& channel,
3 const ptz_camera::init_session_request_t* req)
4 {
5 std::cout << "Received init session req on channel: " << channel <<
6 "; Camera: " << req->ip_address << std::endl;
7
8 auto ip_address = req->ip_address;
9
10 // Note use of std::shared_ptr
11 auto init_session_response = make_shared<ptz_camera::init_session_response_t>();
12
13 auto key_position = this->ip_client_map.find(ip_address);
14 if (key_position == ip_client_map.end())
15 {
16 std::cout << "Creating a new client for the ip: "
17 << req->ip_address << endl;
18
19 wstring username = this->convert_to_wstring(req->username);
20 wstring password = this->convert_to_wstring(req->password);
21
22 wstring main_uri = L"http://" + convert_to_wstring(ip_address);
23 auto config = http_client_config();
24 auto login = credentials(username, password);
25 config.set_credentials(login);
26 config.set_timeout(std::chrono::milliseconds(500));
27
28 http_client* client = new http_client(main_uri, config);
29 std::cout << "Client created...\n";
30
31 uri_builder uri = uri_builder(U("/") + uri_constants::stw_cgi).
32 append_path(uri_constants::attributes_cgi).append_path(uri_constants::attributes);
33
34 auto request = uri.to_string();
35
36 client->request(methods::GET, request)
37 .then([this, ip_address, client, init_session_response]
38 (pplx::task<http_response> request_task) -> pplx::task<wstring>
39 {
40 try
41 {
42 auto response = request_task.get();
43 if (response.status_code() == status_codes::OK)
44 {
45 std::cout << "Saving client...";
46 this->ip_client_map[ip_address] = client;
47 std::cout << "success.\n";
48
49 init_session_response->status_code =
50 ptz_camera::status_codes_t::OK;
51 }
52
53 else
54 {
55 cout << "GET request to client failed! HTTP Error: "
56 << response.status_code() << std::endl;
57
58 init_session_response->status_code =
59 ptz_camera::status_codes_t::ERR;
60 }
61
62 return response.extract_string();
63 }
64
65 catch (const exception& e)
66 {
67 cout << "Caught exception: " << e.what() << endl;
68 return create_task([e, this]() -> wstring
69 {
70 return convert_to_wstring(e.what());
71 });
72 }
73
74 })
75 .then([init_session_response, this](wstring response)
76 {
77 string n = this->convert_to_string(response);
78 init_session_response->response_message = n;
79 });
80 }
81
82
83 else
84 {
85 string message = "Client for ip: " + req->ip_address + " already exists\n";
86 cout << message << endl;
87 init_session_response->response_message = message;
88 init_session_response->status_code = ptz_camera::status_codes_t::OK;
89 }
90
91 this->lcm->publish(ptz_camera_channels::init_session_res_channel,
92 init_session_response.get());
93}

When you get violation access error, you must have deleted the pointer in some place in your code (e.g. in some then lambdas), but you did not post your code using raw pointer so I can not say which line.
By using std::shared_ptr, when it's passed to the lambda, it's captured by value, so it increase the use_count and ensures that init_session_response is valid and not destructed in the labmda, which solves the issue.

Related

Py_InitializeEx(0) fails after Py_Finalize (after previous initialization) [duplicate]

This question already has answers here:
Py_initialize / Py_Finalize not working twice with numpy
(2 answers)
Closed 9 months ago.
The question is about Python.h (embedded Python 3.10). Here in this minimal example where I Py_Initialize, import numpy and then Py_DecRef it. After that I Py_Finalize and repeat the process one more time:
#include <Python.h>
#include <memory>
#include <iostream>
class Pyth
{
public:
explicit Pyth()
{
size_t len = 11;
auto pname = Py_DecodeLocale("PythonCrash", &len);
Py_SetProgramName(pname);
Py_InitializeEx(0);
auto *mname = PyUnicode_FromWideChar(L"numpy", 5);
auto *pmod = PyImport_Import(mname);
Py_DecRef(mname);
if (pmod)
Py_DecRef(pmod);
}
~Pyth()
{
std::cerr << "Fin: " << Py_FinalizeEx() << std::endl;
}
};
int main()
{
int i = 2;
while (i > 0) {
std::cerr << "Go: " << i << std::endl;
auto* ptr = new Pyth();
std::cerr << "new pyth" << std::endl;
delete ptr;
std::cerr << "del pyth" << std::endl;
--i;
}
return 0;
}
I'm getting an error after I try to finalize for the second time but stacks shows it's on second initialization attampt. The error does not appear if I won't do any work (that is, if I just initialize and finalize in a loop).
Here is the output:
17:27:41: Debugging /home/sms/build-PythonCrash-Desktop-Debug/PythonCrash ...
Go: 2
new pyth
Fin: 0
del pyth
Go: 1
new pyth
Fin: Traceback (most recent call last):
File "/usr/lib64/python3.10/site-packages/numpy/__init__.py", line 150, in <module>
from . import core
File "/usr/lib64/python3.10/site-packages/numpy/core/__init__.py", line 22, in <module>
from . import multiarray
File "/usr/lib64/python3.10/site-packages/numpy/core/multiarray.py", line 12, in <module>
from . import overrides
File "/usr/lib64/python3.10/site-packages/numpy/core/overrides.py", line 7, in <module>
from numpy.core._multiarray_umath import (
SystemError: /builddir/build/BUILD/Python-3.10.4/Objects/structseq.c:481: bad argument to internal function
0
del pyth
17:27:42: Debugging of /home/sms/build-PythonCrash-Desktop-Debug/PythonCrash has finished with exit code 0.
Here is the stack:
1 PyArray_Item_INCREF
2 PyArray_FromScalar
3 gentype_nonzero_number.lto_priv
4 PyObject_IsTrue.part.0
5 _PyEval_EvalFrameDefault
6 _PyEval_Vector
7 _PyObject_FastCallDictTstate
8 slot_tp_init
9 type_call
10 _PyObject_MakeTpCall
11 _PyEval_EvalFrameDefault
12 _PyEval_Vector
13 _PyEval_EvalFrameDefault
14 _PyEval_Vector
15 method_vectorcall
16 _PyEval_EvalFrameDefault
17 _PyEval_Vector
18 method_vectorcall
19 _PyEval_EvalFrameDefault
20 _PyEval_Vector
21 method_vectorcall
22 _PyEval_EvalFrameDefault
23 _PyEval_Vector
24 _PyEval_EvalFrameDefault
25 _PyEval_Vector
26 _PyEval_EvalFrameDefault
27 _PyEval_Vector
28 _PyObject_VectorcallTstate.lto_priv.5
29 object_vacall
30 _PyObject_CallMethodIdObjArgs
31 PyImport_ImportModuleLevelObject
32 builtin___import__
33 cfunction_call
34 _PyObject_MakeTpCall
35 _PyObject_CallFunctionVa
36 PyObject_CallFunction
37 PyImport_Import
38 PyImport_ImportModule
39 _PyCodecRegistry_Init
40 _PyCodec_Lookup
41 config_get_codec_name
42 init_interp_main
43 pyinit_main
44 Py_InitializeFromConfig
45 Py_InitializeEx
46 Pyth::Pyth (main.cpp, 15)
47 main (main.cpp, 36)
'len' is an internal function of python so you cannot do an assignment. try changing len to "o_locale_len" or, something, shorter but just not 'len'.

How do can I get rid of the blank lines that are created c++?

Edit:
Thank you all for the quick and helpful replies. I got it working now. It was because I had to reset the counter.
I have come to ask for help as my professor is not giving me the help I need. I am new to c++ and I am trying to program a program that displays all the integers from 1 to 100 that are divisible by 6 or 7, but not both. and I have to display 5 numbers per row. I got it working except I have blank lines forming in certain areas. I don't know if it's because of how I set up the counter or what.
Here is what I got.
#include <iostream>
using namespace std;
int main()
{
int counter = 0; // Counter for creating new lines after 5 numbers
for (int numRange = 1; numRange <= 100; ++numRange) // Starts the loop of number 1 to 100
{
if (numRange % 6 == 0 || numRange % 7 == 0) // Makes the numbers divisible by 6 and 7
{
cout << numRange << " "; // Displays the output of the divisible numbers
counter++; // Starts the counter
}
if (counter % 5 == 0) // using the counter to create new lines after 5 numbers displayed
{
cout << endl; // Creates a new line
}
}
return 0;
}
This is what is outputted:
6 7 12 14 18
21 24 28 30 35
36 42 48 49 54
56 60 63 66 70
72 77 78 84 90
91 96 98
and this is what it's supposed to look like
6 7 12 14 18
21 24 28 30 35
36 48 49 54 56
60 63 66 70 72
77 78 90 91 96
98
The problem that you're seeing is due to the fact that you are checking for "5 outputs" on every loop, rather than only on ones where a number has been output! So, to fix this issue (there are others), put the counter % 5 == 0 test inside the preceding if block:
for (int numRange = 1; numRange <= 100; ++numRange) // Starts the loop of number 1 to 100
{
if (numRange % 6 == 0 || numRange % 7 == 0) // Makes the numbers divisible by 6 and 7
{
cout << numRange << " "; // Displays the output of the divisible numbers
counter++; // Increments the counter
if (counter % 5 == 0) // Only need this if we have done some output!
{
cout << endl; // Creates a new line
}
}
}
Another problem is that, in this requirement:
that are divisible by 6 or 7, but not both
your code doesn't check for the "but not both" part (but that's not the 'title' question, and I'm not going to do all your homework in one fell swoop).

Does view::join require copyable inner range? Why?

Suppose that we have
cppcoro::generator<int> gen_impl(int in) {
const auto upper = in + 10;
for (; in < upper; ++in)
co_yield in;
}
cppcoro::generator<cppcoro::generator<int>> gen() {
for (int n = 1; n < 100; n += 10)
co_yield gen_impl(n);
}
So we can iterate inner range just fine
for (auto&& row : gen() ) {
for (auto n : row)
std::cout << n << ' ';
std::cout << '\n';
}
NOTE: range-for on ref is required because cppcoro::generator doesn't allow copying (deleted copy ctor)
Print
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90
91 92 93 94 95 96 97 98 99 100
But when we try to "flattern" with view::join
auto rng = gen();
for (auto n : rng | ranges::view::join) {
std::cout << n << '\n';
};
It seems view::join require Copyable inner range?
In file included from <source>:3:
In file included from /opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/view.hpp:38:
In file included from /opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/view/for_each.hpp:23:
/opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/view/join.hpp:320:50: error: call to deleted constructor of 'cppcoro::generator<cppcoro::generator<int> >'
return join_view<all_t<Rng>>{all(static_cast<Rng&&>(rng))};
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/view/view.hpp:112:21: note: in instantiation of function template specialization 'ranges::v3::view::join_fn::operator()<cppcoro::generator<cppcoro::generator<int> > &, false, nullptr>' requested here
v.view_(static_cast<Rng&&>(rng))
^
/opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/utility/functional.hpp:731:42: note: in instantiation of function template specialization 'ranges::v3::view::view<ranges::v3::view::join_fn>::pipe<cppcoro::generator<cppcoro::generator<int> > &, ranges::v3::view::view<ranges::v3::view::join_fn> &, false, nullptr>' requested here
pipeable_access::impl<Pipe>::pipe(static_cast<Arg&&>(arg), pipe)
^
<source>:35:21: note: in instantiation of function template specialization 'ranges::v3::operator|<cppcoro::generator<cppcoro::generator<int> > &, ranges::v3::view::view<ranges::v3::view::join_fn>, false, nullptr>' requested here
for (auto n : rng | ranges::view::join) {
^
/opt/compiler-explorer/libs/cppcoro/include/cppcoro/generator.hpp:174:3: note: 'generator' has been explicitly marked deleted here
generator(const generator& other) = delete;
^
/opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/view/join.hpp:76:36: note: passing argument to parameter 'rng' here
explicit join_view(Rng rng)
^
What makes this not compiled?
Is there any bug in range-v3 or cppcoro?
Only incompatible design decisions?
godbolt (Full)
In range-v3, a move-only view is OK. That got implemented late and there may still be bugs, but that's not what is happening here.
The first problem is that you are trying to adapt an lvalue of type cppcoro::generator here:
auto rng = gen();
for (auto n : rng | ranges::view::join) {
Since a generator is a view, the join view will want to copy it. It can't because it is not copyable.
You can fix this problem by moving the generator in:
auto rng = gen();
for (auto n : std::move(rng) | ranges::view::join) {
Then you run into the next problem, which is that the reference type of generator<generator<int>> is const generator<int>&, and you have the same problem again: the join wants to hold a copy of the inner generator while it iterates over it, but it cannot make a copy.
The workaround is a bit ugly: change the generator to return a non-const lvalue reference:
cppcoro::generator<cppcoro::generator<int>&> gen() {
for (int n = 1; n < 100; n += 10) {
auto tmp = gen_impl(n);
co_yield tmp;
}
}
and then std::move each inner range with a move view:
auto rng = gen();
for (auto n : std::move(rng) | ranges::view::move | ranges::view::join) {
std::cout << n << '\n';
}
The result compiles. Whether it runs or not depends on how gracefully cppcoro handles the case where someone steals away the guts of the value that it safely tucked away in the coroutine's promise type.
https://godbolt.org/z/mszidX
A note about the future std::view::join:
The join view that will ship with C++20 is a little different. If the outer range's reference type is a real reference (as in this case), it will not try to make a copy of the view to which it refers. That means in C++20, you won't need the ugly view::move hack.
However, the C++20 View concept currently requires copyability so this solution still won't work. We have a TODO item to relax this before C++20 ships, but there's no telling how the Committee will like that idea.

How do I call the value in array and change the value in array?

class DataStorage{
// 0 1 2 3 4 5 6 7 8
string Data[20][4]={{"Wee","50","1","First"},{"Wee","22","2","First"},
// 9 10 11 12 13 14 15 16
{"Jason","26","3","First"},{"Krappa","12","4","First"},
// 17 18 19 20 21 22 23 24
{" "," ","5","First"},{" "," ","6","Economy"},
//25 26 27 28 29 30 31 32
{"Kappa","15","7","Economy"},{"Eraser","17","8","Economy"},
//33 34 35 36 37 38 39 40
{" "," ","9","Economy"},{"Morty"," ","10","Economy"},
//41 42 43 44 45 46 47 48
{"Rick"," ","11","Economy"},{"Amanda","10","12","Economy"},
//49 50 51 52 53 54 55 56
{"Lee","","13","Economy"},{"MingLee"," ","14","Economy"},
//57 58 59 60 61 62 63 64
{"Beauty"," ","15","Economy"},{"S4head"," ","16","Economy"},
//65 66 67 68 69 70 71 72
{"Ivan"," ","17","Economy"},{"Dex"," ","18","Economy"},
//73 74 75 76 77 78 79 80
{"Chua"," ","19","Economy"},{"Haha"," ","20","Economy"},};
};
int main(){
}
How do I call the value in array and change the value in array? Do I need to make some function to get value from the input and pass it into a variable in class and set it into my array?
I'm not sure what you're asking when you say How do I call the value in array and change the value in array? but I think you're asking how do you change the value of an array element.
To modify an array element you assign the array's index to what you're changing the array's element to; however, remember that C++ arrays are 0-index arrays meaning when you start counting their elements at 0. For example the following code modifies the element at index 5. Live preview
#include <iostream>
int array[10] = {1, 5, 33, 7, -23, 2, 8, 54, 19, 2};
int main() {
std::cout << array[5] << std::endl;
array[5] = 100; // Set the value of the element at index 5 to 100
std::cout << array[5] << std::endl;
return 0;
}
If you want to have Data as a class member of DataStorage you have to initialize it in the member initialization list. I also highly recommend to use an abstraction for the bare array, like std::array. This allows to use bounds-checked access with the at() function. You can then access Data and change it's contents.
#include <array>
#include <iostream>
#include <string>
class DataStorage
{
public:
std::array<std::array<std::string,4>,20> Data;
DataStorage() : Data({{
{{"Wee","50","1","First"}},
{{"Wee","22","2","First"}},
{{"Jason","26","3","First"}},
{{"Krappa","12","4","First"}},
{{" "," ","5","First"}},
{{" "," ","6","Economy"}},
{{"Kappa","15","7","Economy"}},
{{"Eraser","17","8","Economy"}},
{{" "," ","9","Economy"}},
{{"Morty"," ","10","Economy"}},
{{"Rick"," ","11","Economy"}},
{{"Amanda","10","12","Economy"}},
{{"Lee","","13","Economy"}},
{{"MingLee"," ","14","Economy"}},
{{"Beauty"," ","15","Economy"}},
{{"S4head"," ","16","Economy"}},
{{"Ivan"," ","17","Economy"}},
{{"Dex"," ","18","Economy"}},
{{"Chua"," ","19","Economy"}},
{{"Haha"," ","20","Economy"}}
}}) {}
};
int main()
{
DataStorage d;
std::cout << d.Data.at(10).at(2) << '\n'; // prints 11
d.Data.at(10).at(2) = "1729";
std::cout << d.Data.at(10).at(2) << '\n'; // prints 1729
}

Decimate vector in eigen

I have a float array Eigen::ArrayXf which I need to decimate (i.e. pick 1 out of f.i. 8 samples).
Eigen::ArrayXf decimatedSignal = Eigen::Map<Eigen::ArrayXf, 0, Eigen::InnerStride<8> >(signal.data(), length, 1).eval();
which works, with a caveat: I need to know how long length is, and it can be specified too long, leading to runtime errors.
Q: is there a way to decimate all that is possible, so that resultant length is == signal.size() / 8 ?
Two things. You are using the c'tor for mapping a matrix:
Map (
PointerArgType dataPtr,
Index nbRows,
Index nbCols,
const StrideType & a_stride = StrideType()
)
Constructor in the dynamic-size matrix case.
Parameters
dataPtr pointer to the array to map
nbRows the number of rows of the matrix expression
nbCols the number of columns of the matrix expression
a_stride optional Stride object, passing the strides.
I think you want the c'tor for a vector:
Map ( PointerArgType dataPtr,
Index a_size,
const StrideType & a_stride = StrideType()
)
Constructor in the dynamic-size vector case.
Parameters
dataPtr pointer to the array to map
a_size the size of the vector expression
a_stride optional Stride object, passing the strides.
The second thing is that you want length == signal.size())/8. Is that always a whole integer, or are you rounding up? If the data is 16 in length and you want the positions [0] and [8], then use 1+(signal.size()-1)/8 as the length parameter:
Eigen::ArrayXf decimatedSignal = Eigen::Map<Eigen::ArrayXf, 0, Eigen::InnerStride<8> >(signal.data(), 1+((signal.size()-1)/8) ).eval();
For example:
#include <Eigen/Core>
#include <iostream>
using std::cout;
using std::endl;
int main(int argc, char *argv[])
{
Eigen::VectorXf signal;
signal.setLinSpaced(64, 0.0, 63.);
cout << "Original signal:" << endl << signal.transpose() << endl;
Eigen::ArrayXf decimatedSignal = Eigen::Map<Eigen::ArrayXf, 0,
Eigen::InnerStride<8> >(signal.data(), 1+((signal.size()-1)/8)).eval();
cout << endl << "Decimated:" << endl << decimatedSignal.transpose() << endl;
return 0;
}
outputs
Original signal:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
Decimated:
0 8 16 24 32 40 48 56
which I think is exactly what you want.