Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Storing objects in a list

    SDK Help
    0
    31
    15.9k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H
      Helper
      last edited by

      On 20/05/2013 at 16:47, xxxxxxxx wrote:

      Fair warning.
      The GeArray types are the only officially supported lists(arrays). And they are cross platform too AFAIK.
      Maxon does not like it when we use things like the Standard Library. If you use it, you are on your own. And they will not help you with any code problems if you are using it.

      With that disclaimer out of the way.
      Try it like this and see if it works better for you:

      //This example uses the Standard Library instead of the C4D API to store objects into a list array  
      //WARNING!!: Maxon does not like it when you do this. And will probably ignore requests for help if you use it!  
        
      #include <c4d.h>  
      #include <list>  
      using namespace std;  
        
        
        BaseDocument *doc = GetActiveDocument();  
        
        list<BaseObject*> objects;                 //Create an empty list array  
        
        BaseObject *obj = doc->GetFirstObject();   //Start the iteration from the first object in the OM  
        if(!obj) return FALSE;  
         
        while (obj)  
        {  
            objects.push_back(obj);                //Store the objects in the list array  
            obj = obj->GetNext();  
        }  
          
        list<BaseObject*>::iterator it;  
        for (it=objects.begin(); it != objects.end(); it++)  
        {   
            BaseObject *listObj = *it;  
            String name = listObj->GetName();  
            GePrint(name);  
        
            //etc...  
        }
      

      -ScottA

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        On 20/05/2013 at 17:19, xxxxxxxx wrote:

        Thanks! In the man time I got it working. I never wanted to store a BaseObject*, I want to store my own class instances.
        But initially I asked for a way to use Maxon approved lists. Because I suspected that cross platform code has to be catered for. And I believe the BaseContainer is such. So if you read my original post in this thread, I come to a point where I can store objects, but not read them.
        If I could use the BaseContainer or any other "container" I would be interested.

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 20/05/2013 at 17:42, xxxxxxxx wrote:

          I've never tried to store a custom class in a list before. So I can't be of much help with that.

          The GeData class is another common way to store things in C4D. And the docs mention that they can be used for storing custom class types.
          But I must confess I've never even attempted it. So I don't know if that class would be any help.

          -ScottA

          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            On 20/05/2013 at 18:13, xxxxxxxx wrote:

            Ok, I found a way that works.
            To what extent it is patent C++, and furthermore C4D safe, I have no idea.
            But as soon as I understood how you dereference pointers to objects in C++ (I have used it a lot in Pascal), I got something that so far seems to work ok:

             myContainer->SetLong(4, (LONG)&mySpecialClass);
             // Then to get it out again:
             MySpecialClass* mySpecialClass2 = (MySpecialClass* )myContainer->GetLong(4);
             String test = mySpecialClass2->DoSomethingMeaningful();
            

            Hope this will be ok with Mr. Maxon 😉

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              On 20/05/2013 at 23:16, xxxxxxxx wrote:

              Originally posted by xxxxxxxx

              The GeArray types are the only officially supported lists(arrays). And they are cross platform too AFAIK.

              They are not the only supported types. Actually I rather recommend against using GeArray types, as they are rather slow, seen from nowadays standards. Use c4d_misc::BaseArray<> instead, if you need arrays. They are blazing fast, support sorting and iterators, and have almost no overhead.
              Or, if you want it the old-fashioned way, how about a simple AtomArray?

              Originally posted by xxxxxxxx

              So thank you, the std::list is precisely what I need!! Great!

              Objection, your honor.

              Originally posted by xxxxxxxx

              Maxon does not like it when we use things like the Standard Library. If you use it, you are on your own.

              Exactly 🙂

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                On 20/05/2013 at 23:42, xxxxxxxx wrote:

                My fault, sorry. You first have to dereference the iterator. 🙂

                (*it)->GetName()
                

                Ingvar, using a container for this is really not a good idea I think. 1. the BaseContainer is intended
                as a mapping type, 2. you need to do a cast every-time you want to access. Not that this will have
                any cause on the performance on the program, but results in clunky and large code.

                You can use the GeDynamicArray class from the Cinema SDK as well (as I have already mentioned
                in my first answer).

                #include <ge_dynamicarray.h>
                  
                GeDynamicArray<BaseObject*> objects;
                  
                // Store the top-level objects in a list.
                BaseObject* op = doc->GetFirstObject();
                while (op) {
                    objects.Push(op);
                    op = op->GetNext();
                }
                  
                // Iterate over them again.
                LONG count = objects.GetCount();
                for (LONG i=0; i < count; i++) {
                    BaseObject* obj = objects[i];
                    // ...
                }
                

                PS: Code is untested, intended to give you a small overview over the usage only.

                Best,
                -Nik

                1 Reply Last reply Reply Quote 0
                • H
                  Helper
                  last edited by

                  On 21/05/2013 at 00:16, xxxxxxxx wrote:

                  ...OR you can use a shiny BaseArray instead of the dusty GeDynamicArray 😛

                  1 Reply Last reply Reply Quote 0
                  • H
                    Helper
                    last edited by

                    On 21/05/2013 at 00:21, xxxxxxxx wrote:

                    Is it much faster than the GeDynamicArray? I must admit that I have not yet taken a look
                    into the c4d_misc namespace. From the name, I always thought it would be a fixed size array. 😊

                    1 Reply Last reply Reply Quote 0
                    • H
                      Helper
                      last edited by

                      On 21/05/2013 at 01:41, xxxxxxxx wrote:

                      Never assume, always look 🙂 The fact that BaseArray has methods like Push(), Insert() and Resize() tells you it's dynamic.

                      And about the speed: The BaseArray is not just faster, it's ridiculously fast. Really.

                      Here's some code I just wrote to benchmark it (as I didn't have any concrete numbers) :

                      void MyBench(LONG cnt)   
                      {   
                           GeDynamicArray<Real> dynamicArray;   
                           c4d_misc::BaseArray<Real> baseArray;   
                           LONG i;   
                           LONG timer = 0;   
                        
                           Real x = 3.14165;   
                        
                           GePrint("Array Benchmark (" + LongToString(cnt) + ")");   
                        
                           // Push()   
                           GePrint("GeDyamicArray::Push()...");   
                           timer = GeGetTimer();   
                           for (i = 0; i < cnt; i++)   
                           {   
                                dynamicArray.Push(x);   
                           }   
                           GePrint("..." + LongToString(GeGetTimer() - timer) + " msec.");   
                        
                           GePrint("BaseArray::Push()...");   
                           timer = GeGetTimer();   
                           for (i = 0; i < cnt; i++)   
                           {   
                                baseArray.Append(x);   
                           }   
                           GePrint("..." + LongToString(GeGetTimer() - timer) + " msec.");   
                        
                           // Reading   
                           GePrint("GeDynamicArray[]...");   
                           timer = GeGetTimer();   
                           for (i = 0; i < cnt; i++)   
                           {   
                                x = dynamicArray[i];   
                           }   
                           GePrint("..." + LongToString(GeGetTimer() - timer) + " msec.");   
                        
                           GePrint("BaseArray[]...");   
                           timer = GeGetTimer();   
                           for (i = 0; i < cnt; i++)   
                           {   
                                x = baseArray[i];   
                           }   
                           GePrint("..." + LongToString(GeGetTimer() - timer) + " msec.");   
                        
                           // Pop()   
                           GePrint("GeDynamicArray::Pop()...");   
                           timer = GeGetTimer();   
                           for (i = 0; i < cnt; i++)   
                           {   
                                x = dynamicArray.Pop();   
                           }   
                           GePrint("..." + LongToString(GeGetTimer() - timer) + " msec.");   
                        
                           GePrint("BaseArray::Pop()...");   
                           timer = GeGetTimer();   
                           for (i = 0; i < cnt; i++)   
                           {   
                                x = baseArray.Pop();   
                           }   
                           GePrint("..." + LongToString(GeGetTimer() - timer) + " msec.");   
                        
                           GePrint("Array Benchmark finished.");   
                      }   
                      

                      I built it using the latest Intel Compiler (version 13) as a 64 Bit Release build and ran it with different cnt values:

                      MyBench(10000);   
                      MyBench(100000);   
                      MyBench(1000000);   
                      

                      And here are the results (on a 27" iMac with 3.4Ghz i7 and 8GB RAM) :

                        
                      10000 elements   
                                         Push           []           Pop   
                      GeDynamicArray     1 msec        0 msec       5 msec   
                      BaseArray          0 msec        0 msec       0 msec   
                        
                      100000 elements   
                                         Push           []           Pop   
                      GeDynamicArray     602 msec       0 msec       602 msec   
                      BaseArray          0 msec        0 msec       0 msec   
                        
                      1000000 elements   
                                         Push           []           Pop   
                      GeDynamicArray     272085 msec    0 msec       271149 msec   
                      BaseArray          9 msec        0 msec       0 msec   
                      

                      By the way, GeAutoDynamicArray and GeSafeDynamicArray are even slower.

                      1 Reply Last reply Reply Quote 0
                      • H
                        Helper
                        last edited by

                        On 21/05/2013 at 01:58, xxxxxxxx wrote:

                        Thanks Jack, this is a very useful resource! Those differences in speed are tremendous! You convinced
                        me rather using the BaseArray instead.. 😉

                        Best,
                        -Nik

                        1 Reply Last reply Reply Quote 0
                        • H
                          Helper
                          last edited by

                          On 21/05/2013 at 02:58, xxxxxxxx wrote:

                          Uhm, how do I copy a BaseArray to another BaseArray? Copy&Assign is disallowed for the BaseArray
                          class. I get compiler errors when doing

                          array1 = array2
                          

                          "" error C2248: 'c4d_misc::BaseArray<T>::operator =' : cannot access private member declared in class 'c4d_misc::BaseArray<T>' ""

                          Thanks,
                          -Niklas

                          1 Reply Last reply Reply Quote 0
                          • H
                            Helper
                            last edited by

                            On 21/05/2013 at 03:02, xxxxxxxx wrote:

                            Nevermin, just found the "CopyFrom" method. 😂

                            1 Reply Last reply Reply Quote 0
                            • H
                              Helper
                              last edited by

                              On 21/05/2013 at 03:30, xxxxxxxx wrote:

                              Wow - what an interesting thread!
                              I thank you all for all new knowledge. I have a few comments though. My experience in general, is that while you can make speed tests, they are not always reliable. You have something called a compiler which lives its own superior life and is the ultimate decision maker. Certain ways of doing things might be fast in one situation, slow in another.
                              Anyhow - for the plugins I write, my speed concern is purely to speed up me. To get things done. My  current plugins execute more than fast enough, regardless of list implementation.
                              But I like what I see about the BaseArray, so I will go for that one.

                              1 Reply Last reply Reply Quote 0
                              • H
                                Helper
                                last edited by

                                On 21/05/2013 at 05:07, xxxxxxxx wrote:

                                Of course, the compiler is responsible for the final performance. Anyway, if one array type takes 272085 msec to accomplish a certain task, and another type takes 9 msec, it's pretty obvious that the first type will always be the slower one.

                                1 Reply Last reply Reply Quote 0
                                • H
                                  Helper
                                  last edited by

                                  On 21/05/2013 at 07:34, xxxxxxxx wrote:

                                  You can't blame me too much for not recommending the the BaseArray Frank.
                                  Because the only rolled out in the in R14. And like most people. I'm still using older versions. 😉

                                  I've been wondering what's the benefit for putting a class inside of a container?
                                  The class is always there. And you can create an instance of it whenever you want. So I don't understand what benefit comes from stuffing it into a B.C.?
                                  Where (in what case) would you need to use such a thing?

                                  -ScottA

                                  1 Reply Last reply Reply Quote 0
                                  • H
                                    Helper
                                    last edited by

                                    On 21/05/2013 at 08:10, xxxxxxxx wrote:

                                    Sorry to hear that BaseArray => R14 
                                    In any case, it is right up my alley, exactly what I need. And it works just great.

                                    1 Reply Last reply Reply Quote 0
                                    • H
                                      Helper
                                      last edited by

                                      On 21/05/2013 at 08:20, xxxxxxxx wrote:

                                      It would now be interesting to see how this performs against a std::list Jack

                                      1 Reply Last reply Reply Quote 0
                                      • H
                                        Helper
                                        last edited by

                                        On 21/05/2013 at 09:23, xxxxxxxx wrote:

                                        I must say that I am impressed. 🙂
                                        Didn't expect the AtomArray to be fairly fast! And the std library to be so slow.. And the
                                        GeDynamicArray is really slow compared to all of those! Must be some very rusty piece of
                                        list implementation? 🙂

                                        Benchmarks in the next post, the previous results were from a debug build.

                                        Code:

                                        #include <c4d.h>
                                          
                                        #include <ge_dynamicarray.h>
                                        #include <list>
                                        #include <vector>
                                          
                                        String* g_mode;
                                          
                                        void StartTest(String mode) {
                                            GePrint("Starting Test: " + mode);
                                            if (!g_mode) g_mode = new String;
                                            *g_mode = mode;
                                        }
                                          
                                        void AddStats(String type, LONG delta) {
                                            LONG l = type.GetLength();
                                            for (LONG i=l; l <= 20; l++) {
                                                type += " ";
                                            }
                                          
                                            if (!g_mode) g_mode = new String("FOO");
                                          
                                            GePrint(type + " " + *g_mode + ": " + LongToString(delta) + "ms");
                                        }
                                          
                                        void Bench(LONG x) {
                                            AutoAlloc<AtomArray> atomarr;
                                            GeDynamicArray<BaseObject*> gda;
                                            c4d_misc::BaseArray<BaseObject*> ba;
                                            std::list<BaseObject*> list;
                                            std::vector<BaseObject*> vector;
                                            LONG i, tstart, delta;
                                          
                                            BaseObject* test = BaseObject::Alloc(Onull);
                                            if (!test) {
                                                GeDebugOut("No object could be allocated.");
                                                return;
                                            }
                                            AutoFree<BaseObject> test_free(test);
                                          
                                            GePrint("Benchmark started with " + LongToString(x) + " elements.");
                                            GePrint("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
                                          
                                            StartTest("Adding Elements");
                                          
                                            // Atom Array
                                            tstart = GeGetTimer();
                                            for (i=0; i < x; i++) {
                                                atomarr->Append(test);
                                            }
                                            delta = GeGetTimer() - tstart;
                                            AddStats("AtomArray", delta);
                                          
                                            // GeDynamicArray
                                            tstart = GeGetTimer();
                                            for (i=0; i < x; i++) {
                                                gda.Push(test);
                                            }
                                            delta = GeGetTimer() - tstart;
                                            AddStats("GeDynamicArray", delta);
                                          
                                            // BaseArray
                                            tstart = GeGetTimer();
                                            for (i=0; i < x; i++) {
                                                ba.Append(test);
                                            }
                                            delta = GeGetTimer() - tstart;
                                            AddStats("BaseArray", delta);
                                          
                                            // std::list
                                            tstart = GeGetTimer();
                                            for (i=0; i < x; i++) {
                                                list.push_back(test);
                                            }
                                            delta = GeGetTimer() - tstart;
                                            AddStats("std::list", delta);
                                          
                                            // std::vector
                                            tstart = GeGetTimer();
                                            for (i=0; i < x; i++) {
                                                vector.push_back(test);
                                            }
                                            delta = GeGetTimer() - tstart;
                                            AddStats("std::vector", delta);
                                          
                                            StartTest("Iteration");
                                          
                                            // AtomArray
                                            tstart = GeGetTimer();
                                            for (i=0; i < x; i++) {
                                                (void) atomarr->GetIndex(i);
                                            }
                                            delta = GeGetTimer() - tstart;
                                            AddStats("AtomArray", delta);
                                          
                                            // GeDynamicArray
                                            tstart = GeGetTimer();
                                            for (i=0; i < x; i++) {
                                                (void) gda[i];
                                            }
                                            delta = GeGetTimer() - tstart;
                                            AddStats("GeDynamicArray", delta);
                                          
                                            // BaseArray
                                            tstart = GeGetTimer();
                                            for (i=0; i < x; i++) {
                                                (void) ba[i];
                                            }
                                            delta = GeGetTimer() - tstart;
                                            AddStats("BaseArray", delta);
                                          
                                            // std::list
                                            tstart = GeGetTimer();
                                            std::list<BaseObject*>::iterator list_it = list.begin();
                                            for (; list_it != list.end(); list_it++) {
                                                (void) *list_it;
                                            }
                                            delta = GeGetTimer() - tstart;
                                            AddStats("std::list", delta);
                                          
                                            // std::vector
                                            tstart = GeGetTimer();
                                            std::vector<BaseObject*>::iterator vector_it = vector.begin();
                                            for (; vector_it != vector.end(); vector_it++) {
                                                (void) *vector_it;
                                            }
                                            delta = GeGetTimer() - tstart;
                                            AddStats("std::vector", delta);
                                        }
                                          
                                        class Test : public CommandData {
                                          
                                        public:
                                          
                                            Bool Execute(BaseDocument* doc) {
                                                Bench(10000);
                                                Bench(100000);
                                                Bench(1000000);  
                                                Bench(10000000);
                                                return TRUE;
                                            }
                                          
                                        };
                                          
                                          
                                        Bool PluginStart() {
                                            return RegisterCommandPlugin(1000023, "Benchmark", PLUGINFLAG_COMMAND_HOTKEY, NULL,
                                                                         "Benchmark for List Types", gNew Test);
                                            return TRUE;
                                        }
                                          
                                        Bool PluginMessage(LONG type, void* pData) {
                                            return TRUE;
                                        }
                                          
                                        void PluginEnd() {
                                        }
                                        
                                        1 Reply Last reply Reply Quote 0
                                        • H
                                          Helper
                                          last edited by

                                          On 21/05/2013 at 09:41, xxxxxxxx wrote:

                                          Here it is, the new benchmark:

                                          Benchmark started with 10000 elements.
                                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                          Starting Test: Adding Elements
                                          AtomArray             Adding Elements: 0ms
                                          GeDynamicArray        Adding Elements: 0ms
                                          BaseArray             Adding Elements: 0ms
                                          std::list             Adding Elements: 1ms
                                          std::vector           Adding Elements: 0ms
                                          Starting Test: Iteration
                                          AtomArray             Iteration: 0ms
                                          GeDynamicArray        Iteration: 0ms
                                          BaseArray             Iteration: 0ms
                                          std::list             Iteration: 1ms
                                          std::vector           Iteration: 0ms
                                            
                                          Benchmark started with 100000 elements.
                                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                          Starting Test: Adding Elements
                                          AtomArray             Adding Elements: 2ms
                                          GeDynamicArray        Adding Elements: 10ms
                                          BaseArray             Adding Elements: 1ms
                                          std::list             Adding Elements: 6ms
                                          std::vector           Adding Elements: 2ms
                                          Starting Test: Iteration
                                          AtomArray             Iteration: 0ms
                                          GeDynamicArray        Iteration: 0ms
                                          BaseArray             Iteration: 0ms
                                          std::list             Iteration: 1ms
                                          std::vector           Iteration: 0ms
                                            
                                          Benchmark started with 1000000 elements.
                                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                          Starting Test: Adding Elements
                                          AtomArray             Adding Elements: 20ms
                                          GeDynamicArray        Adding Elements: 5060ms
                                          BaseArray             Adding Elements: 18ms
                                          std::list             Adding Elements: 43ms
                                          std::vector           Adding Elements: 15ms
                                          Starting Test: Iteration
                                          AtomArray             Iteration: 3ms
                                          GeDynamicArray        Iteration: 0ms
                                          BaseArray             Iteration: 0ms
                                          std::list             Iteration: 7ms
                                          std::vector           Iteration: 0ms
                                            
                                          Benchmark started with 10000000 elements.
                                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                          Starting Test: Adding Elements
                                           **AtomArray             Adding Elements: 180ms**
                                           **GeDynamicArray        Adding Elements: 550471ms**
                                           **BaseArray             Adding Elements: 170ms**
                                           **std::list             Adding Elements: 454ms**
                                           **std::vector           Adding Elements: 236ms**
                                          Starting Test: Iteration
                                           **AtomArray             Iteration: 34ms**
                                           **GeDynamicArray        Iteration: 0ms**
                                           **BaseArray             Iteration: 0ms**
                                           **std::list             Iteration: 70ms**
                                           **std::vector           Iteration: 0ms**
                                          

                                          Now that I have compiled in release mode, the differences between the std library and the
                                          Cinema 4D API or not that huge anymore, but still signifficant!

                                          -Niklas

                                          1 Reply Last reply Reply Quote 0
                                          • H
                                            Helper
                                            last edited by

                                            On 21/05/2013 at 09:58, xxxxxxxx wrote:

                                            Thanks first of all Niklas! but of course you have to call .reserve() before iterating the vector container when doing push_backs to give a fair comparison (and resize for lists...).

                                            dereferencing is slower than direct access which is not suprising but good to know!

                                            1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post