Setting fields of a Matlab struct in C++

7 visualizzazioni (ultimi 30 giorni)
Daniel
Daniel il 17 Ago 2011
Modificato: Alan Frankel il 12 Giu 2019
I have a compiled Matlab function that takes a structure as input. I'm trying to initialize that structure from C++, using the mwArray framework. Let's say the structure just has fields "a", "b", and "c".
First I'm going to create a 1x1 structure array with those fields (I'm not going to delete anything in this example, but assume deletion happens later at the right time):
fields = new char*[3];
fields[0] = "a"; fields[1] = "b"; fields[2] = "c";
mwSize dims[2] = {1,1};
mwArray* inputArray = new mwArray(2, dims, 3, (const char**)fields);
I can confirm that this array has 3 fields with the right names and 1 element using NumberOfFields(), GetFieldName(), and NumberOfElements().
Now I'm going to make mwArray's that I'll use to set the fields:
double a=1,b=2,c=3;
mwArray field0Value(1, 1, mxDOUBLE_CLASS, mxREAL);
mwArray field1Value(1, 1, mxDOUBLE_CLASS, mxREAL);
mwArray field2Value(1, 1, mxDOUBLE_CLASS, mxREAL);
field0Value.SetData(&a, 1);
field1Value.SetData(&b, 1);
field2Value.SetData(&c, 1);
Now I have three individual one-element double arrays. I can confirm that these are properly set using NumberOfElements() and GetData().
Now here's the core of my question...
* How do I assign these values to the fields of inputArray? *
My first instinct, consistent with the only example I could find online, was to do this:
inputArray->Get(fields[0],1,1).Set(field0Value);
But this doesn't work... calling "Get(fields[0],1,1)" seems to produce a deep copy of the field I'm interested in, so this line does nothing to inputArray. If I call:
inputArray->Get(fields[0],1,1).NumberOfElements()
...immediately after executing the "Set()", it still has 0 elements. If I store the temporary variable I get from inputArray->Get(fields[0],1,1), I can set its data. This all tells me that the Get() operation is performing a copy, and I'm not really accessing inputArray.
This is all confirmed when I try to pass inputArray to my Matlab function; it's empty.
* So how do I actually put data into a struct array? *
Thanks!
-Dan

Risposte (6)

Kaustubha Govind
Kaustubha Govind il 17 Ago 2011
I think you might need to use operator(). Try:
inputArray(fields[0],1,1) = field0Value;

Daniel
Daniel il 17 Ago 2011
I think using operator() gives me the same result... if I do this:
// Assign field0Value into the struct using operator()
(*inputArray)(fields[0],1,1) = field0Value;
// How big is field0Value?
int field0size = field0Value.NumberOfElements();
Console::WriteLine("Field 0 has {0} elements", field0size);
// How big is field 0 of inputArray?
int nElements = inputArray->Get(fields[0],1,1).NumberOfElements(); Console::WriteLine("First struct field has {0} elements", nElements);
This tells me that:
Field 0 has 1 elements
First struct field has 0 elements
In other words, the assignment didn't take; operator() appears to also return a copy.
Any other ideas?
Thanks!
-Dan

Daniel
Daniel il 17 Ago 2011
I'm OK for now because I got this working using the C versions of the compiled functions, using mxArrays. mxSetFieldByNumber() behaves exactly the way I want. But I still figure there must be some way to assign values to a Matlab struct in C++ (mwArray), and it's a little odd that some of my code is in C++ and some is in C now.
Thanks!
-Dan
  2 Commenti
Kaustubha Govind
Kaustubha Govind il 18 Ago 2011
Strange. This solution seems to suggest that using Get() like you did should work: http://www.mathworks.com/support/solutions/en/data/1-2VHBW8/index.html
The only difference is that you are using an mwArray pointer, but I can't think of why that could be a problem.
ClemensM
ClemensM il 2 Lug 2015
Hi.
I am having exact the same problem on Windows. On Linux i have used mwArray structure creation exactly like described above and it works.
The thing that really is really annoying is that this is at least since MATLAB R2009a like that and still is in R2014a. It is a little hard to believe that an API that is unsusable on Windows has never been fixed.
Is it possible that somewone at Mathworks sets up a little test example on Windows and if successful provides it to us?
Thanks,
Clemens

Accedi per commentare.


Alexey Krutikhin
Alexey Krutikhin il 26 Ago 2015
I found a solution - try to use GetA() instead of Get(). It works for me.

Steven Lord
Steven Lord il 26 Ago 2015
I haven't tried this, and this is well outside my usual area of expertise, but from reading the documentation and cobbling together pieces of examples I think something like this should work.
// Create the struct and get an mwArray for its field 'a'
const char* fields[] = {"a", "b", "c"};
mwArray mystruct(1, 1, 3, fields);
mwArray fieldA = mystruct.Get("a", 1, 1);
// Create the data to store in the field
mwArray f(2, 2, mxDOUBLE_CLASS);
f(1, 1) = 1;
f(1, 2) = 2;
f(2, 1) = 3;
f(2, 2) = 4;
// This last is from the documentation for the SET method, described as "Assign shared copy of"
// input array to currently referenced cell for arrays of type mxCELL_CLASS and mxSTRUCT_CLASS."
fieldA.Set(f);

Alan Frankel
Alan Frankel il 12 Giu 2019
Modificato: Alan Frankel il 12 Giu 2019
I tried this with both MATLAB R2014b and R2019b. I found that, unlike Daniel, I am able to set the struct field using mwArray (C++) code whether I:
  1. chain the calls to Get() and Set(), or
  2. store the result of the Get() call in a named variable before calling Set() on it
Here's my version of the driver code (where my code does not call "new", so does not need to call "delete"):
const char* fields[] = {"a", "b", "c"};
mwSize dims[2] = {1,1};
mwArray inputArray(2, dims, 3, fields);
double a=1,b=2,c=3;
mwArray field0Value(1, 1, mxDOUBLE_CLASS, mxREAL);
mwArray field1Value(1, 1, mxDOUBLE_CLASS, mxREAL);
mwArray field2Value(1, 1, mxDOUBLE_CLASS, mxREAL);
field0Value.SetData(&a, 1);
field1Value.SetData(&b, 1);
field2Value.SetData(&c, 1);
std::cout << "EXAMPLE 1: Chain the calls to Get() and Set()." << std::endl;
std::cout << "before: inputArray.Get(fields[0],1,1).NumberOfElements(): " <<
inputArray.Get(fields[0],1,1).NumberOfElements() << std::endl;
std::cout << "before: inputArray.Get(fields[0],1,1): "
<< inputArray.Get(fields[0],1,1) << std::endl;
inputArray.Get(fields[0],1,1).Set(field0Value);
std::cout << "after: inputArray.Get(fields[0],1,1).NumberOfElements(): " <<
inputArray.Get(fields[0],1,1).NumberOfElements() << std::endl;
std::cout << "after: inputArray.Get(fields[0],1,1): "
<< inputArray.Get(fields[0],1,1) << std::endl << std::endl;
std::cout << "EXAMPLE 2: Don't chain the calls to Get() and Set()." << std::endl;
std::cout << "before: inputArray.Get(fields[1],1,1).NumberOfElements(): " <<
inputArray.Get(fields[1],1,1).NumberOfElements() << std::endl;
std::cout << "before: inputArray.Get(fields[1],1,1): "
<< inputArray.Get(fields[1],1,1) << std::endl;
mwArray field = inputArray.Get(fields[1],1,1);
field.Set(field1Value);
std::cout << "after: inputArray.Get(fields[1],1,1).NumberOfElements(): " <<
inputArray.Get(fields[1],1,1).NumberOfElements() << std::endl;
std::cout << "after: inputArray.Get(fields[1],1,1): "
<< inputArray.Get(fields[1],1,1) << std::endl;
And here's the output:
EXAMPLE 1: Chain the calls to Get() and Set().
before: inputArray.Get(fields[0],1,1).NumberOfElements(): 0
before: inputArray.Get(fields[0],1,1): []
after: inputArray.Get(fields[0],1,1).NumberOfElements(): 1
after: inputArray.Get(fields[0],1,1): 1
EXAMPLE 2: Don't chain the calls to Get() and Set().
before: inputArray.Get(fields[1],1,1).NumberOfElements(): 0
before: inputArray.Get(fields[1],1,1): []
after: inputArray.Get(fields[1],1,1).NumberOfElements(): 1
after: inputArray.Get(fields[1],1,1): 2

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by