Here I have simple program:
struct A{
int t=0;
operator() (int *p) {cout << "operator() (int *p)\n";delete p;};
~A() {cout << "~A\n";};
};
int main(int argc, char** argv) {
{
unique_ptr<int, A> u(new int[9]{0});
}
return 0;
}
The program creates an unique_ptr on array of int. And use callable object A to destroy pointer. All is simple. But when I run the program the output is:
~A
operator() (int *p)
~A
I don't understand why destructor calling two time. If there is some idea?
The unique_ptr takes a copy of the deleter object by feature to preserve the state, for more information.
https://stackoverflow.com/a/35318283/4669663
Here is the code I've tried to confirm that the copy constructor is invoked for deleter when unique_ptr is created,
http://cpp.sh/7yqw2
On my Computer with g++ (GCC) 7.1.1 20170516 I get the output
$ ./test2
operator() (int *p)
~A
with your programm.
It will depend on your compiler and standard library implementation. Probably std::unique_ptr makes an additional copy of an object of type A and the source is then probably destroyed.
In my search, I found that it's better to use default_delete<>()
shared_ptr<int> u(new int[9], default_delete<int[]>());
Related
The current C++ compilers fail to find a suitable overload for std::shared_ptr when using a C-array as a type.
I can make it a real std::array object and that works, but the library I'm linking against (fftw3) has already created the typedef and uses it in all of it's C-API calls.
#include <memory>
typedef double fftw_complex[2];
int main(int argc, char* argv[])
{
fftw_complex bob; //works fine
bob[0]=2; bob[1]=-1; //works fine
std::shared_ptr<fftw_complex> handle; //works fine
std::shared_ptr<double> other(new double[35]); //works fine
handle = std::shared_ptr<fftw_complex>(new fftw_complex[35]);//can't find constructor
return 0;
}
Up until a few months ago this worked fine with all compilers. With the update to gcc to version 7.3, 8.2, and 9 I now get an error when trying to compile the non-void constructor. I suspect it is because of the "improvements" to std::shared_ptr to automatically handle when T is an array type.
I get the error
complex_shared.cpp:12:61: error: no matching function for call to 'std::shared_ptr<double [2]>::shared_ptr(double (*)[2])'
12 | handle = std::shared_ptr<fftw_complex>(new fftw_complex[35]);
and the somewhat difficult to parse error message
note: candidate: 'template<class _Yp, class> std::shared_ptr<_Tp>::shared_ptr(_Yp*)'
139 | shared_ptr(_Yp* __p) : __shared_ptr<_Tp>(__p) { }
| ^~~~~~~~~~
/usr/local/Cellar/gcc/9.2.0/include/c++/9.2.0/bits/shared_ptr.h:139:2: note: template argument deduction/substitution failed:
/usr/local/Cellar/gcc/9.2.0/include/c++/9.2.0/bits/shared_ptr.h: In substitution of 'template<class _Tp> template<class ... _Args> using _Constructible = typename std::enable_if<std::is_constructible<std::__shared_ptr<_Tp>, _Args ...>::value>::type [with _Args = {double (*)[2]}; _Tp = double [2]]':
/usr/local/Cellar/gcc/9.2.0/include/c++/9.2.0/bits/shared_ptr.h:137:30: required from here
/usr/local/Cellar/gcc/9.2.0/include/c++/9.2.0/bits/shared_ptr.h:106:8: error: no type named 'type' in 'struct std::enable_if<false, void>'
106 | using _Constructible = typename enable_if<
it seems you have to let std::shared_ptr know that this is not a normal pointer but is indeed a pointer to an array
#include <memory>
typedef double fftw_complex[2];
int main(int argc, char* argv[])
{
fftw_complex bob;
bob[0]=2; bob[1]=-1;
std::shared_ptr<fftw_complex[]> handle;
std::shared_ptr<double> other(new double[35],[](double* p){ delete[] p;});
std::shared_ptr<double[]> nother(new double[35]); //std::shared_ptr will call delete[]
handle = std::shared_ptr<fftw_complex[]>(new fftw_complex[35], [](fftw_complex* p){ /* special delete logic*/;});
return 0;
}
to be clear, I have to use the fftw_malloc and fftw_free functions for this memory, so I will be providing my own deleter for the fftw_complex type. delete[] is incorrect for these library-provided data elements.
Simplified code snippet is:
class A {
public:
~A();
static A create();
private:
A() = default;
A(A&&) = default;
NonCopyable n;
};
A A::create() {
A a;
return a;
}
int main(int argc, char* argv[]) {
auto a = A::create();
return 0;
}
Please also see my live example (which shows different compilers' behavior).
In the end, I'm wondering why does auto a = A::create(); compile without errors using newer compilers [gcc >= 7.1] (which part of the C++17 standard is relevant here?), given that:
We have a non-copyable member NonCopyable n;, so default copy constructor would be ill-formed.
It's an NRVO here since A a; return a; so copy elision is not guaranteed by the standard.
Move constructor A(A&&) is marked private.
Optimizations were off -O0 for testing.
My suspicion is that move constructor is being "validated" by the compiler at return a;; since this is a member function of A it passes the validation. Even if the suspicion is correct, I'm not sure if this is standard-compliant.
I believe this is a consequence of P0135: Wording for guaranteed copy elision through simplified value categories, specifically the change to [dcl.init]:
If the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object.
[Example: T x = T(T(T())); calls the T default constructor to initialize x. — end example]
As a result, this behavior is not dependent on copy elision of return values or the availability of move constructors.
in C++, if a method is accepting left reference + pointer only,
it seems it suffices if we only have a template method with T& as its parameter, why we usually overload with test(T* ) as well ?
proof of concept: left reference method can take pointer argument.
#include <iostream>
using namespace std;
template<class T>
void test(T& arg) {
T value = arg;
cout << *value << endl;
}
int main() {
int b = 4;
int* a = &b;
test(a); // compiles and runs without issue.
return 0;
}
Why [do] we usually overload with test(T* ) as well?
I am not sure that we usually do anything of the sort, but if one were to overload for a pointer, it would be because pointers behave differently than object types. Remember, a pointer in fact is not an object but an address to an object.
The reason that test(a) compiles and runs without issue is because it is accepting a reference to a pointer to an object as its parameter. Thus, when the line cout << *value << endl; executes, the pointer is dereferenced back to an object and we see 4 printed to standard out.
As #HolyBlackCat mentioned, we usually want do different things for T& and T*.
As indicated in the example, for test(T&) we usually need to manually do dereference, this would result in the difference in the behavior, so it makes sense to have a overload like this.
I have an issue. I'm trying to convert a void* to std::function.
This is just a simple example, any suggestions will be appreciated
#.h file
class Example {
public:
Example();
int foo(void* hi);
int fooFunc(std::function<int(int, int)> const& arg, int x, int y) {
foo(arg.target<void*>(), x, y);
return 2;
}
};
#.cpp file
Example::Example() {
}
int Example::foo(void * func, int x, int y)
{
//cast back to std::function
func(x, y);
std::cout << "running in foo: " << a << "\n";
return a;
}
Every casting i tried did not work.
I know i can send a std::function in this example, but it's for something bigger and i'm working on an example to make it work here.
The whole meaning of void*, is for sometimes to use it, in these situations, when you don't know what you will receive, and then cast it to the specific usage you need.
Thanks!
You can't.
You can cast a data pointer to void* and then back to the same pointer type you have started with. std::function is not a pointer type, so the cast is statically invalid, and it's not the same thing you have started with. You have started with a .target of type void(*)() but it's not a data pointer, it's a function pointer, so casting it to void* and back is implementation-defined.
You can:
Ignore the issue and cast to void(*)() anyway. Will work on most (but not all) platforms.
Use void(*)() instead of void* as a universal function pointer (you can cast it to other function types).
Use whatever tools C++ offers to avoid the cast altogether.
I'm having trouble with std::initializer_list. I reduced it down to a simple example:
#include <initializer_list>
#include <cstdio>
class Test {
public:
template <typename type> Test(const std::initializer_list<type>& args) {}
};
int main(int argc, char* argv[]) {
Test({1,2});
getchar();
return 0;
}
When compiled using g++ test_initializer.cpp -std=c++0x, it compiles and runs well. However, if line 11 is changed to Test({1,2.0});, one gets:
ian#<host>:~/Desktop$ g++ test_initializer.cpp -std=c++0x
test_initializer.cpp: In function ‘int main(int, char**)’:
test_initializer.cpp:11:14: error: no matching function for call to ‘Test::Test(<brace-enclosed initializer list>)’
test_initializer.cpp:11:14: note: candidates are:
test_initializer.cpp:7:28: note: template<class type> Test::Test(const std::initializer_list<_Tp>&)
test_initializer.cpp:5:7: note: constexpr Test::Test(const Test&)
test_initializer.cpp:5:7: note: no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘const Test&’
test_initializer.cpp:5:7: note: constexpr Test::Test(Test&&)
test_initializer.cpp:5:7: note: no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘Test&&’
I suspect this happens because the compiler can't figure out what type to make the initializer list. Is there a way to fix the example so that it works with different types (and still uses initializer lists)?
An std::initializer_list takes only one type. If you need different types, you can use variadic templates:
template<typename... Args>
Test(Args&&... args);
/* ... */
int main()
{
Test(1, 2.0);
}
Would a std::tuple<int.double> work for the OP? If the code will always have a int followed by a double, then the OP could get strict type-checking for all arguments, which the variable arguments solution does not allow. The std::tuple<>, however, would not work for any number or order of values, so may not be appropriate for all use cases.
Let the initializer_list hold the most arbitrary pointers, void*, and do your own casting from there. Here is an example.
#include <initializer_list>
#include <iostream>
using std::initializer_list;
using std::cout;
using std::endl;
class Person {
private:
string _name;
int _age;
public:
Person(initializer_list<void*> init_list) {
auto it = init_list.begin();
_name = *((string*)(*it));
it++;
_age = *((int*)(*it));
}
void print() {
cout << "name: " << _name << ". age: " << _age << endl;
}
};
int main(void) {
string name{"Vanderbutenburg};
int age{23};
Person p{&name,&age};
p.print(); // "name: Vanderbutenburg. age: 23"
return 0;
}