Hi all I'm having trouble with C++ template operator=
What I'm trying to do:
I'm working on a graph algorithm project using cuda and we have several different formats for benchmarking graphs. Also, I'm not entirely sure what type we'll end up using for the individual elements of a graph.
My goal is to have a templated graph class and a number of other classes, each of which will know how to load a particular format. Everything seems to work alright except the point where the graphCreator class returns a graph type from the generate function.
Here is my code:
Graph opertator=:
MatrixGraph<T>& operator=(MatrixGraph<T>& rhs)
{
width = rhs.width;
height = rhs.height;
pGraph = rhs.pGraph;
pitch = rhs.pitch;
sizeOfGraph = rhs.sizeOfGraph;
rhs.Reset();
}
the rhs.reset() call removes all references to allocated memory so they will not be deallocated by rhs. Only one graph is allowed to have a reference to the allocated graph memory.
Graph copy constructor:
MatrixGraph(MatrixGraph<T>& graph)
{
(*this) = graph;
}
Graph Creator load function:
MatrixGraph<T> LoadDIMACSGraphFile(std::istream& dimacsFile)
{
char inputType;
std::string input;
GetNumberOfNodesAndEdges(dimacsFile, nodes, edges);
MatrixGraph<T> myNewMatrixGraph(nodes);
while(dimacsFile >> inputType)
{
switch(inputType)
{
case 'e':
int w,v;
dimacsFile >> w >> v;
myNewMatrixGraph[w - 1][v - 1] = 1;
myNewMatrixGraph[v - 1][w - 1] = 1;
break;
default:
std::getline(dimacsFile, input);
break;
}
}
return myNewMatrixGraph;
}
And finally in main.cpp where I'm trying to unit test this I use it:
DIMACSGraphCreator<short> creator;
myGraph = creator.LoadDIMACSGraphFile(instream);
When I try to compile I get this error:
main.cpp: In function 'int main(int, char**)':
main.cpp:31: error: no match for 'operator=' in 'myGraph = DIMACSGraphCreator<T>::LoadDIMACSGraphFile(std::istream&) [with T = short int](((std::istream&)(& instream.std::basic_ifstream<char, std::char_traits<char> >::<anonymous>)))'
MatrixGraph.h:103: note: candidates are: MatrixGraph<T>& MatrixGraph<T>::operator=(MatrixGraph<T>&) [with T = short int]
make: *** [matrixTest] Error 1
just a guess, are you by chance missing const qualifiers in your copy constructor and assignment?
The problem is you're returning by value (correctly) but trying to bind that temporary object to a non-const reference (for the op= parameter). You can't do this.
The solution is to change things around, which can result in non-idiomatic code; use an auto_ptr_ref-like construct, which gets around this in a fairly bad-but-encapsulated way; or use r-value references, which are designed for exactly this situation. However, r-value references are only available as part of C++0x, and your compiler may not support them yet.
Make sure to return *this in your op= as well. Without warnings turned on your compiler may silently (and against the standard) accept that function without a return statement. (I don't know why.)
Example of the first solution:
// move return value into output-parameter:
void LoadDIMACSGraphFile(std::istream& dimacsFile, MatrixGraph<T>& dest);
// ...
DIMACSGraphCreator<short> creator;
creator.LoadDIMACSGraphFile(instream, myGraph);
std::auto_ptr is in the the stdlib, and uses a special "holder" class named auto_ptr_ref to implement move semantics.
Related
This might seem like a trivial issue, but I can't seem to find a solution.
What I have:
void VideoHandler::demoBurn(QString fileName) {
// Create a reader for a video
openshot::FFmpegReader r("raw_videos/example0.mp4");
r.Open(); // Open the target reader
// Create a writer
openshot::FFmpegWriter w("edited_videos/NewVideo.mp4");
w.SetAudioOptions(true, "libvorbis", 44100, 2, openshot::ChannelLayout::LAYOUT_STEREO, 128000);
w.SetVideoOptions(true,"libx264" , openshot::Fraction(30,1), r.info.width, r.info.height, openshot::Fraction(1,1), false, false, 300000);
w.Open();
openshot::Timeline t(r.info.width,r.info.height, r.info.fps, 44100,2, openshot::ChannelLayout::LAYOUT_STEREO);
// Clip example
openshot::Clip c1(new openshot::QtImageReader("edited_videos/0.png"));
c1.Layer(1);
c1.Position(5.9);
c1.Start(5.9);
c1.End(10.0);
c1.scale = openshot::SCALE_NONE;
c1.gravity = openshot::GRAVITY_TOP_LEFT;
c1.location_x = 0.0;
c1.location_y = 0.2;
std::list<openshot::Clip> clipList;
for (int i = 0; i < 2; i++) {
QString imageName = QString("edited_videos/%1.png").arg(i);
clipList.push_back(openshot::Clip(new openshot::QtImageReader(imageName.toUtf8().toStdString())));
}
// Add clip values and add to timeline
std::list<openshot::Clip>::iterator it;
int test = 0;
for (it = clipList.begin(); it != clipList.end(); it++) {
it->Layer(1);
if(test == 0) {
it->Position(5.9);
it->Start(5.9);
it->End(10.0);
} else {
it->Position(10.0);
it->Start(10.0);
it->End(15.0);
}
it->scale = openshot::SCALE_NONE;
it->gravity = openshot::GRAVITY_TOP_LEFT;
it->location_x = 0.0;
it->location_y = 0.2;
test++;
t.AddClip(&it);
}
// Add clips to timeline
t.AddClip(&c1);
openshot::Clip c2(new openshot::FFmpegReader("raw_videos/example0.mp4"));
c2.Position(0.0);
c2.Layer(0);
t.AddClip(&c2);
// Open the timeline reader
t.Open();
// Close the timeline reader
w.WriteFrame(&t, 1, r.info.video_length);
// Close the reader & writer
t.Close();
w.Close();
r.Close();
}
I'm using libopenshot to burn some image overlays to the video, and since I don't know how many images there will be, I need to dynamically create a openshot::Clip for each one and give it some values.
I saw some examples on dynamic object allocation and thought this should work, but I'm getting compile errors:
/usr/include/c++/7/ext/new_allocator.h:136: error: use of deleted function ‘openshot::Clip::Clip(const openshot::Clip&)’
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
/home/3rdparty/libopenshot/include/Clip.h:95: error: ‘juce::CriticalSection::CriticalSection(const juce::CriticalSection&)’ is private within this context
And for t.AddClip(&it) error:
cannot initialize a parameter of type 'openshot::Clip *' with an rvalue of type 'std::list<openshot::Clip>::iterator *' (aka '_List_iterator<openshot::Clip> *')
I can somewhat understand this error, but how do I give it the right pointer, I thought the it would hold the pointer to the object?
Since I never done dynamic object allocation, I'm not sure if this is the right way of doing it, am I using a wrong type of list?
std::list<openshot::Clip>::iterator it;
...
t.AddClip(&it);
I thought the it would hold the pointer to the object?
When you use the addressof operator - i.e. the unary & operator - on a value, what you get is pointer to that object. In this case, you use &it, and therefore you get a pointer to it. it is an iterator to a list.
However, AddClip is not expecting a pointer to an iterator. It is expecting a pointer to a openshot::Clip object. That is why you get the error:
cannot initialize a parameter of type [pointer to clip] with an rvalue of type [pointer to iterator]
I don't see how this could be affected by what the iterator "holds".
How might you get a pointer to a clip object? You apply the addressof operator on such object - rather than applying addressof operator on an object of some other type such as an iterator.
How might you get a clip object? You have an iterator to such object; you can indirect through the iterator to get the object.
How might you indirect through an iterator? You use the indirection operator i.e. the unary * operator.
For example:
t.AddClip(&*it);
Since I never done dynamic object allocation, I'm not sure if this is the right way of doing it
I don't know of openshot, so I cannot be certain, but those bare new expressions seem dubious. Unless that API mandates it, you should probably be using a unique pointer assuming dynamic allocation is needed in the first place.
After many trial and error, I managed to get it to work. What I changed is:
created a list of pointers (doesn't matter if it's QList or std:list, tested and both work the same)
and re-referenced all the iteration objects with pointers to the actual object.
Thanks to #eerorika for the info about (&*it)
QList<openshot::Clip*> clipList;
for (int i = 0; i < 2; i++) {
QString imageName = QString("edited_videos/%1.png").arg(i);
clipList.push_back(new openshot::Clip(new openshot::QtImageReader(imageName.toUtf8().toStdString())));
}
// Add clip values and add to timeline
QList<openshot::Clip*>::iterator it;
int test = 0;
for (it = clipList.begin(); it != clipList.end(); it++) {
(*it)->Layer(1);
if(test == 0) {
(*it)->Position(5.9);
(*it)->Start(5.9);
(*it)->End(10.0);
} else {
(*it)->Position(10.0);
(*it)->Start(10.0);
(*it)->End(15.0);
}
(*it)->scale = openshot::SCALE_NONE;
(*it)->gravity = openshot::GRAVITY_TOP_LEFT;
(*it)->location_x = 0.0;
(*it)->location_y = 0.2;
test++;
t.AddClip(&*(*it));
}
I use std::vector<double> in some of my logic, but mainly the operator[]. Some data is coming from google's protocol buffer library in a repeated field. An example for the proto file:
message My_message{
repeated double numbers = 1;
}
So far I've only been using vectors, and converted the protobuf field to vector as described in another question.
void my_function(const std::vector<double> my_numbers){
...
double i_shall_copy_this = my_numbers[0];
std::copy(my_numbers.begin(),my_numbers.end(), inside_vector.begin());
...
}
int main(){
My_message my_msg;
...
std::vector<double> my_vec = {my_msg.numbers().begin(),my_msg.numbers().end()};
my_function(my_vec);
return 0;
}
Unfortunately this comes with unnecessary copying of data, which I would like to avoid. To avoid copying I would like to use references.
void my_function(const std::vector<double>& my_numbers){
...
}
int main(){
My_message my_msg;
...
my_function({my_msg.numbers().begin(),my_msg.numbers().end()}); //(1)
my_function(reinterpret_cast<std::vector<double>>(my_msg.numbers())); //(2)
return 0;
}
So far, adding it by temporary works( //(1) ), but it involves copying.
Despite the fact that both google::protobuf::RepeatedField and std::vecDor implements operator[], a reinterpret cast have failed //(2) :
error: invalid cast from type ‘const google::protobuf::RepeatedField<double>’ to type ‘std::vector<double>’
So a solution I have been thinking about is to add a third type, which requires only operator[] and the iterators implemented ( and a contiguous guarantee ).
Unfortunately common inheritance is not an option here: Both types come from official libraries, and I am just a mortal unworthy of maintaining a fork of those for a project. What options do I have here?
This is what templates are for. Since you only need the passed in type to have an operator[], you can make the function a template:
template<typename Container>
void my_function(const Container & my_numbers) {
// use my_numbers[42] for example
}
and now this will compile for any type that has operator[] defined for it.
So now there is no need to convert the google::protobuf::RepeatedField<double> to a temporary std::vector<double>.
I'm still new to C++ and have come across a problem where I can't seem to insert a new derived class to a map.
My code is simplified as follows:
std::map<int, std::unique_ptr<Base_Class> > m;
void func(){
for(int num = 0; num < 100; n++){
m.emplace(num, new Derived_Class() );
}
}
Which gives me this:
error: no matching function for call to 'std::pair <const int, std::unique_ptr<Base_Class> >::pair(int&, Derived_Class*)
I've tried unsuccessfully using:
m.emplace(std::pair(num, new Derived_Class()) );
And which gives me this:
error: no matching function for call to 'std::pair<const int, std::unique_ptr<Base_Class> >::pair(std::pair<int, Derived_Class*>)
I can't seem to figure this one out and would appreciate any help.
m.emplace(num, std::unique_ptr<Derived_Class>(new Derived_Class()));
Would be the way to go. Since the unique_ptr constructor taking a raw pointer is explicit, it cannot be implicitly initialized from a Derived_Class*. You need to explicitly create a unique_ptr object to emplace.
I posed this solution because you mentioned c++11, but the truly favorable way would be to use std::make_unique<Derived_Class>() (c++14 and onward), both to avoid repeating yourself, and to make the creation of the unique_ptr "atomic".
Am getting a huge compile error with message
c:\mingw\include\c++\6.1.0\bits\predefined_ops.h:123:18: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Deduction; _Dp = std::default_delete<Deduction>]'
{ return bool(_M_comp(*__it1, *__it2)); }
when I pass a custom comparator to STL set_difference function.
My code:
struct Value{
std::string ded_code;
float amount;
Value(std::string code, float amt):ded_code(code), amount(amt){}
};
struct Deduction{
std::string p_number;
std::vector<std::unique_ptr<Value>> values;
Deduction(string pnum, string code, float amt):p_number(pnum){
auto val = std::make_unique<Value>(code, amt);
values.emplace_back(move(val));
}
};
class compute{
public:
vector<unique_ptr<Deduction>> deductions;
void fillDeductions(){
// fill deductions
...
}
};
class CompareDiff{
public:
bool operator()(unique_ptr<Deduction>& ded1, unique_ptr<Deductions>& ded2){
rPtr1 = ded1.get();
rPtr2 = ded2.get();
return ( rPtr1->p_number < rPtr2->p_number);
}
};
...
int main(){
...
// fill two deduction vectors
Compute compA = Compute()
compA.fillDeductions()
Compute compB = Compute()
compB.fillDeductions()
vector<unique_ptr<Deduction>> diffs
set_difference(compA.begin(), compA.end(),
compB.begin(), compB.end(),
inserter(diffs, diffs.begin()), CompareDiff());
}
Am using gcc 6.1.0 on windows 7 machine.
What am I missing?
Regards.
PG
The reason why you are still getting an error:
std::set_difference does copy internally:
Copies the elements from the sorted range [first1, last1) which are not found in the sorted range [first2, last2) to the range beginning at d_first.
http://en.cppreference.com/w/cpp/algorithm/set_difference
If you want your code to compile, use std::shared_ptr instead.
Keep in mind, that the Standard Library is optimized for Objects and not for pointers. You will have to do the ownership management yourself if you use pointers.
The chief feature of std::unqiue_ptr is that it cannot be copied. That's by design, and the name tells you as much.
However, CompareDiff tries to take its arguments by value. That requires a copy. Instead, take a std::unique_ptr<..> const& - no copy is needed.
You cannot copy construct a unique_ptr since its a deleted function, you can move unique pointers to transfer ownership but since you want a functor to compare something you need to pass those unique_ptr by reference.
Use a unique_ptr<x> to express that a function assumes ownership of an x.
Use a shared_ptr<x> to express that a function is part owner of an x.
If you indeed want to pass a unique_ptr and transfer ownership, you should move the smart pointer into the function argument.
More notes on passing smart pointers, and Herb Sutter has some good thoughts in this CppCon talk.
In an attempt to wrap some unmanaged code in a managed .dll I'm trying to convert a Generic::List of data points into a std::vector. Here's a snippet of what I'm trying to do:
namespace ManagedDLL
{
public ref class CppClass
{
void ListToStdVec( const List<double>& input_list, std::vector<double>& output_vector )
{
// Copy the contents of the input list into the vector
// ...
}
void ProcessData( List<double> sampleData )
{
std::vector<double> myVec;
ListToStdVec( sampleData, myVec );
// Now call the unmanaged code with the new vector
// ...
}
}
}
Compiling this gives me:
error C3699: '&' : cannot use this indirection on type 'const System::Collections::Generic::List'
I've probably missed something fundamental here (I'm relatively new to .net's way of doing things), but that looks like reasonably valid code to me.. ?
[Edit] I've tried both Andy and Dario's suggestions and they work, but how do I then access the members of the input list? I've tried all sorts of combinations of dreferencing and nothing seems to compile:
void ListToStdVec( const List<double>% input_list, std::vector<double>& output_vector )
{
int num_of_elements = input_list->Count;
}
void ListToStdVec( const List<double>^ input_list, std::vector<double>& output_vector )
{
int num_of_elements = input_list.Count;
}
...both give me:
error C2662: 'System::Collections::Generic::List::Count::get' : cannot convert 'this' pointer from 'const System::Collections::Generic::List' to 'System::Collections::Generic::List %'
...so how do you access the reference / pointer?
According to Herb Sutter, % is the managed object pass by reference character. Convert the code to the following, and it should work:
void ListToStdVec( const List<double>% input_list, std::vector<double>& output_vector
{
// Copy the contents of the input list into the vector
// ...
}
Edit: I think the const is causing the issues, although I'm not sure why. If you change the List argument to not be const, then the first function will compile if you use the -> operator, while the second function will compile if you use the . operator (I'm not sure why that difference exists - it doesn't make much sense).
That said, if all that you want to do is to copy the elements in the List to the vector, then you really want to use ^. Think of that as having a reference to the managed object. I think that % would be used if you want to pass the reference "by reference" (i.e. reassign input_list to something else within ListToStdVec(), and have the caller see the result of that assignment. However, given that you use the . operator to access members when using %, that tells me that I may not understand the purpose of that at all.
As List<T> is a managed .NET class, it's passed by managed GC-Handle denoted by ^ and not by C++-reference.
Ex:
void ListToVec(List<double>^ input_list, std::vector<double>& out)
You don't need additional const here. The notation List<T>^% creates a tracking reference (comparable to C++-pointers) rather than a call by reference.
Just access the members by list->... and list[...].