Maybe someone can help me understand the error.
I write this code:
class Text
{
private:
struct paragraph
{
vector<string> lines;
};
vector<shared_ptr<paragraph>> paragraphs;
public:
Text()
{
paragraphs.push_back(shared_ptr<paragraph>(new paragraph()));
}
};
int main()
{
shared_ptr<Text> pText(nullptr);
Text text();
pText.reset(&text);
return 0;
}
When I try to run it
I got this error:
1>c:\program files\microsoft visual studio 10.0\vc\include\memory(1664): error C2541: 'delete' : cannot delete objects that are not pointers
1> c:\program files\microsoft visual studio 10.0\vc\include\memory(1431) : see reference to function template instantiation 'void std::tr1::shared_ptr<_Ty>::_Resetp<_Ux>(_Ux (__cdecl *))' being compiled
1> with
1> [
1> _Ty=Text,
1> _Ux=Text (void)
1> ]
1> c:\program files\microsoft visual studio 10.0\vc\include\memory(1607) : see reference to function template instantiation 'std::tr1::shared_ptr<_Ty>::shared_ptr<_Ux>(_Ux (__cdecl *))' being compiled
1> with
1> [
1> _Ty=Text,
1> _Ux=Text (void)
1> ]
1> c:\documents and settings\owner\שולחן העבודה\e\class.cpp(29) : see reference to function template instantiation 'void std::tr1::shared_ptr<_Ty>::reset<Text(void)>(_Ux (__cdecl *))' being compiled
1> with
1> [
1> _Ty=Text,
1> _Ux=Text (void)
1> ]
What is meant "cannot delete objects that are not pointers"?
I'm not trying to delete any object.
In addition to the most vexing parse, your code contains a fundamental flaw:
You must not assign a pointer to a stack-allocated object to a shared_ptr.
This code will cause undefined behaviour which in practice means lots of pain:
shared_ptr<Text> pText(nullptr);
Text text;
pText.reset(&text);
shared_ptr will try to delete &text at the end of its lifetime.
The line Text text(); does not do what you think it does.
It parses it as the declaration of a function named text which accepts no argument and returns a value of type Text.
This is the reason why your line pText.reset(&text); does not compile.
However, you really do not want that line to compile: you are associating a shared_ptr object to a value with automatic storage duration: when the shared_ptr will go out of scope, it will try to delete that object, resulting in Undefined Behavior (most likely a crash in this case).
You main function should read.
int main()
{
shared_ptr<Text> pText(new Text);
return 0;
}
You had 2 problems. First, Text text() was being parsed as a function declaration. Second, you were passing the address of a stack variable to a shared_ptr, which will delete the object when the reference count reaches 0.
You should also consider whether you need to use a shared_ptr. Will you ever be sharing this pointer with any body else, or do you simply want to ensure it is destructed properly? You could consider unique_ptr in the latter case. Do you even need a pointer at all, could you just allocate the object on the stack?
Related
Wanting to investigate the performance hit (if any) of std:function.
I have this struct:
struct InstructionDescription
{
std::string name;
word mask;
word code;
std::function<void(Cpu*, word)> func;
word flags;
};
and I set up a vector of them like this
std::vector<InstructionDescription> instructions_{
{
{"clr", DD_MASK, 0005000, &Cpu::Clr},
{"clrb", DD_MASK, 0105000, &Cpu::Clr},
{"com", DD_MASK, 0005100, &Cpu::Com},
.....
Works fine. Now if I change the struct to use a function pointer:
using InstrFunc = void(*)(Cpu*, word);
struct InstructionDescription
{
std::string name;
word mask;
word code;
InstrFunc func;
word flags;
};
which as far as I can see should be equivalent. And yet I get
1>C:\work\pdp\mysim\mysim\instructions.h(60,50): error C2664: 'std::vector<Cpu::InstructionDescription,std::allocator<Cpu::InstructionDescription>>::vector(std::initializer_list<_Ty>,const _Alloc &)': cannot convert argument 1 from 'initializer list' to 'std::initializer_list<_Ty>'
1> with
1> [
1> _Ty=Cpu::InstructionDescription,
1> _Alloc=std::allocator<Cpu::InstructionDescription>
1> ]
1> and
1> [
1> _Ty=Cpu::InstructionDescription
1> ]
1>C:\work\pdp\mysim\mysim\instructions.h(60,50): message : Element '1': no conversion from 'initializer list' to '_Ty'
1> with
1> [
1> _Ty=Cpu::InstructionDescription
1> ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.25.28610\include\vector(512,5): message : see declaration of 'std::vector<Cpu::InstructionDescription,std::allocator<Cpu::InstructionDescription>>::vector'
1>Console.cpp
VS2019. VS GUI is also highlighting the std::vector line saying 'InstructionDescription' is unknown and that the function names are not accessible (&Cpu::Clr for example)
The Cpu class is defined like:
struct Cpu {
void Clr(word) {};
void Com(word) {};
};
What am I doing wrong?
The std::function is very convenient: it recognizes that &Cpu::Clr is a member function whose first parameter will be a Cpu*.
When you make it a function pointer, this doesn't work like this. You have to use a member function pointer:
using InstrFunc = void (Cpu::*)(word);
Additional info
This is standard: std::function nicely copes with pointers to member functions by adding a pointer to the class as first argument. Of course, when you call it, you have to provide that additional parameter:
Cpu cpu;
for (auto& i:instructions_) {
i.func(&cpu, i.code); // as simple as that with std::function
}
When you go for the pointer to member function, it's less convenient:
Cpu cpu;
for (auto& i:instructions) {
(cpu.*i.func)(i.code);
}
Online demo (you need to comment/ comment out the specific lines)
I know I could do this better with std::vector, but the application I am messing with, has already a bunch of CArray parameters on a lot of related functions ... and I will not change them all at the moment!
I simply want to define an empty CArray<CClass*> — array of pointers to CClass, so the problem can not be on the CClass constructor — as the default value of a function parameter.
Approach 1
If I try to do it with assignment operator and default constructor:
void Function(CArray<CClass*> parameter = CArray<CClass*>());
I get the error:
1>C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\atlmfc\include\afxTempl.h(262): error C2248: 'CObject::CObject' : cannot access private member declared in class 'CObject'
1> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\atlmfc\include\afx.h(535) : see declaration of 'CObject::CObject'
1> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\atlmfc\include\afx.h(510) : see declaration of 'CObject'
1> This diagnostic occurred in the compiler generated function 'CArray<TYPE>::CArray(const CArray<TYPE> &)'
1> with
1> [
1> TYPE=CClass *
1> ]
Approach 2
I also tried with a copy constructor:
void Function(CArray<Class*> parameter(CArray<CClass*>()));
I got the errors:
>File.cpp(line X): error C2664: 'FunctionClass::Function' : cannot convert parameter 1 from 'CArray<TYPE>' to 'CArray<TYPE> (__cdecl *)(CArray<TYPE> (__cdecl *)(void))'
1> with
1> [
1> TYPE=CClass*
1> ]
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
line X: contains a call supplying the parameter to Function, as shown: pFunctionClass->Function(parameter);
1>CFunctionClass.cpp(line Y): error C2511: 'void CFunctionClass::Function(CArray)' : overloaded member function not found in 'CShoePlaceDoc'
1> with
1> [
1> TYPE=CClass*
1> ]
1> FunctionClass.h(line A) : see declaration of 'CFunctionClass'
line Y contains the Function implementation header, as shown: `void CFunctionClass::Function(CArray parameter)
1>File.cpp(line Z): error C2660: 'CClassFunction::Function' : function does not take 0 arguments
line Z: contains a call to Functionwithout supplying it parameters, as shown: pClassFunction->Function();
The approach didn't work, but it got its way towards a conclusion: It is not possible to use a copy-constructor for assigning a default value for a function parameter.
Approach 3
And if I try with a lambda:
void Function(CArray<CClass*> parameter = [] () -> CArray<CClass*>{ return CArray<CClass*> (); } );
, then I will get multiple outputs of these two errors:
1>FunctionClass.h(line A): error C2440: 'default argument' : cannot convert from '`anonymous-namespace'::<lambda2>' to 'CArray<TYPE>'
1> with
1> [
1> TYPE=CClass*
1> ]
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>FunctionClass.h(line B): fatal error C1903: unable to recover from previous error(s); stopping compilation
line A: method declaration
line B: closing } of FunctionClass class that contains Function method
Origin of the problem
The root cause of the problem seems to be the fact that CArray is a class directly derived from CObject, which declares the assignment operator as private:
class AFX_NOVTABLE CObject
{
//...
private:
CObject(const CObject& objectSrc); // no implementation
void operator=(const CObject& objectSrc); // no implementation
//...
}
So, how can I supply an empty array as default value for the parameter?
With this declaration
void Function(CArray<CClass*> parameter /*...*/);
You can't. Calling this function will invoke the private copy constructor of CObject as you have noticed.
What you could do, is to add a object of static CArray<CClass*> in your class and initialize the function with a reference to it. This way it will be empty (as long as you do not populate it...) and you can perform a .IsEmpty() check on it.
private:
static CArray<CClass*> myObj;
//...
void Function(CArray<CClass*> ¶meter = myObj);
Or initialize it to 0. This way you simply check it by if (parameter) or if (NULL == parameter).
void Function(CArray<CClass*> *parameter = NULL);
So I can't seem to properly fill the requirements for this constructor.
DIVA_STATUS DIVA_getObjectDetailsList (
IN BOOL pFirstTime,
IN time_t *initialTime,
IN int pListType,
IN int pObjectsListType,
IN int pMaxListSize,
IN DIVA_STRING pObjectName,
IN DIVA_STRING pObjectCategory
IN DIVA_STRING pMediaName
DIVA_LEVEL_OF_DETAIL pLevelOfDetail,
IN vector<DIVA_STRING> listPosition,
OUT vector<DIVA_OBJECT_DETAILS_LIST> *&pObjectDetailsList
)
The problem seems to be the last line which outputs a vector of classes (???). I'm a little rusty with C++ so I cant recall why you would dereference a reference call (*&).
DIVA_OBJECT_DETAILS_LIST is a class shown below:
class DIVA_OBJECT_DETAILS_LIST {
public:
int listType;
DIVA_STRING siteID;
vector<DIVA_STRING> *listPosition;
vector<DIVA_OBJECT_INFO> *objectInfo;
vector<DIVA_OBJECT_TAPE_INFO> *objectTapeInfo;
};
Here is what I get when I try compiling using VC++ 2008 Express
1>Compiling...
1>initiator.cpp
1>.\initiator.cpp(148) : error C2100: illegal indirection
1>.\initiator.cpp(148) : error C2665: 'DIVA_getObjectDetailsList' : none of the 2 overloads could convert all the argument types
1> z:\Mediavault1\Automation\DIVA_API\DIVArchiveAPI\CppAPI Test\include\DIVAapi.h(2191): could be 'DIVA_STATUS DIVA_getObjectDetailsList(bool,time_t,int,int,int,DIVA_STRING,DIVA_STRING,DIVA_STRING,DIVA_LEVEL_OF_DETAIL,std::vector<_Ty>,DIVA_OBJECT_DETAILS_LIST *&)'
1> with
1> [
1> _Ty=DIVA_STRING
1> ]
1> while trying to match the argument list '(bool, time_t, int, int, int, DIVA_STRING, DIVA_STRING, DIVA_STRING, DIVA_LEVEL_OF_DETAIL, std::vector<_Ty>, DIVA_OBJECT_DETAILS_LIST *)'
1> with
1> [
1> _Ty=DIVA_STRING
1> ]
Here is how I'm calling the constructor:
cr = DIVA_getObjectDetailsList (
_firstTime,
(time_t)_initDate,
(int)DIVA_OBJECTS_LIST,
(int)DIVA_OBJECTS_CREATED_SINCE,
_size,
_name,
_category,
_group,
DIVA_INSTANCE,
*_listType.listPosition,
&*_listType
);
_listType is DIVA_OBJECT_DETAILS_LIST. How do I pass it pointer by reference?
The problem appears to be with the second to last argument. You are passing a std::vector<DIVA_STRING>* when you should just be passing a std::vector<DIVA_STRING> (not a pointer).
But to help your understanding about the last argument, vector<DIVA_OBJECT_DETAILS_LIST>*& is a "reference to pointer to vector<DIVA_OBJECT_DETAILS_LIST>" type. That is, you should pass a pointer and it is passed by reference.
This is a simple and complex question at the same time.
This compiles:
int Test;
vector<int> TEST;
TEST.push_back(Test);
cout << TEST.size();
This does not compile:
fstream Test;
vector<fstream> TEST;
TEST.push_back(Test);
cout << TEST.size();
Is there any particular reason?
Is there a way for me to get a dynamic list of fstreams?
The error message:
1>------ Build started: Project: vector_test, Configuration: Debug Win32 ------
1> vector_test.cpp
1>c:\program files (x86)\microsoft visual studio 10.0\vc\include\fstream(1347): error C2248: 'std::basic_ios<_Elem,_Traits>::basic_ios' : cannot access private member declared in class 'std::basic_ios<_Elem,_Traits>'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\ios(176) : see declaration of 'std::basic_ios<_Elem,_Traits>::basic_ios'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
1> This diagnostic occurred in the compiler generated function 'std::basic_fstream<_Elem,_Traits>::basic_fstream(const std::basic_fstream<_Elem,_Traits> &)'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
The object fstream is not copyable.
If you need to record fstreams in a vector you can declare a std::vector<std::fstream*> and push back the address of the object. Remember that if you save the pointer, then you must ensure that, when you access it, the object is still alive.
In C++ 2011 the concrete stream objects are movable. Howver, to take advantage of this you either need to pass a temporary or allow the object to be moved:
std::vector<std::ofstream> files;
files.push_back(std::ofstream("f1"));
std::ofstream file("f2");
files.push_back(std::move(file));
Note that you can't use the file variable after this as the stream was moved into files.
To use a class with a vector, it must be copyable. fstream is not.
See: C++ std::ifstream in constructor problem
Edit: If you need to have multiple references to the same fstream, you can use shared_ptr to manage them. Try something like:
std::vector< std::shared_ptr<fstream> > TEST
A basic requirement for a type to be pushed into vector is that the object should be copyable, fstream is not copyable and hence you get compiler errors.
Like others have mentioned, fstream is not copyable. You could just do:
vector<fstream> TEST;
TEST.push_back(fstream()); //fstream is created in the vector, no copy needed
And use like this:
fstream& A = TEST[0];
And even iterate like this:
for(fstream& S : TEST){
...
}
I've written a path class in my program for handling heirarchical path structures. I decided to use std::shared_ptr as the standard return type for the whole class since I'm getting rather fond it.
What surprised me is that I was unable to use std::copy or the normal vector.insert(v.begin(), v.end()) to copy elements to/from vectors of shared_ptr. Why is this?
shared_ptr<vector<shared_ptr<bfile>>> butils::bfile::search()
{
shared_ptr<vector<shared_ptr<bfile>>> ret(new vector<shared_ptr<bfile>>());
shared_ptr<vector<shared_ptr<bfile>>> children = getChildren();
//WTF why don't either of these work?
//std::copy(children->begin(), children->end(), back_inserter(ret));
//ret->insert(children->begin(), children->end());
//I've had to resort to doing this....
for (auto c = children->begin(); c != children->end(); c++)
{
ret->push_back(*c);
auto cChildren = (*c)->search();
for (auto cc = cChildren->begin(); cc != cChildren->end(); cc ++)
{
ret->push_back(*cc);
}
}
return ret;
}
When I tried the std::copy() I got:
1>C:\Program Files (x86)\Microsoft
Visual Studio
10.0\VC\include\iterator(21): error C2039: 'const_reference' : is not a
member of 'std::tr1::shared_ptr<_Ty>'
1> with 1> [ 1>
_Ty=std::vector>
1> ] 1>
BFile.cpp(329) : see reference to
class template instantiation
'std::back_insert_iterator<_Container>'
being compiled 1> with 1>
[ 1>
_Container=std::tr1::shared_ptr>>
1> ]
When I tried the insert(v.begin(), v.end()) I got;
1>C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xmemory(208): error C2664: 'std::tr1::shared_ptr<_Ty>::shared_ptr(std::nullptr_t)' : cannot convert parameter 1 from 'std::_Vector_iterator<_Myvec>' to 'std::nullptr_t'
1> with
1> [
1> _Ty=butils::bfile
1> ]
1> and
1> [
1> _Myvec=std::_Vector_val<std::tr1::shared_ptr<butils::bfile>,std::allocator<std::tr1::shared_ptr<butils::bfile>>>
1> ]
I'm not sure I understand either of these compiler errors... Anyone else have a clue?
You're trying to make a back_inserter to the pointer to the vector, rather than the vector itself. Change back_inserter(ret) to back_inserter(*ret) (if you really feel the need to dynamically allocate vectors like that).
insert is failing because you're missing an argument:
ret->insert(ret->begin(), children->begin(), children->end());
The bizarre error message there is because there is a 2-argument overload of insert, with the second argument being an object to insert. The compiler tries to use this, but fails to convert the iterator into the object type.
std::back_inserter expects a sequence, not a std::shared_ptr. Use back_inserter(*ret).
For the second, insert() requires a third parameter here: insert(where_to_insert,start,end)
consider using a std::transform in place of std::copy.
std::transform(children->begin(),
children->end(),
back_inserter(ret),
[](const bfile& in) { return make_shared<bfile>(in); });