আমার কি # ডিফাইন, এনাম বা কনস্ট ব্যবহার করা উচিত?


125

একটি সি ++ প্রকল্পে আমি কাজ করছি, আমার একটি পতাকা ধরণের মান রয়েছে যার চারটি মান থাকতে পারে। এই চারটি পতাকা একত্রিত করা যেতে পারে। পতাকাগুলি ডাটাবেসে রেকর্ডগুলি বর্ণনা করে এবং হতে পারে:

  • নতুন রেকর্ড
  • মুছে ফেলা রেকর্ড
  • পরিবর্তিত রেকর্ড
  • বিদ্যমান রেকর্ড

এখন, প্রতিটি রেকর্ডের জন্য আমি এই বৈশিষ্ট্যটি রাখতে চাই, যাতে আমি একটি এনাম ব্যবহার করতে পারি:

enum { xNew, xDeleted, xModified, xExisting }

যাইহোক, কোডে অন্য জায়গাগুলিতে, আমাকে কোন রেকর্ড ব্যবহারকারীর কাছে দৃশ্যমান হবে তা নির্বাচন করতে হবে, তাই আমি এটি একটি একক প্যারামিটার হিসাবে পাস করতে সক্ষম হতে চাই, যেমন:

showRecords(xNew | xDeleted);

সুতরাং, মনে হচ্ছে আমার কাছে তিনটি সম্ভাব্য অ্যাপোপ্যাক রয়েছে:

#define X_NEW      0x01
#define X_DELETED  0x02
#define X_MODIFIED 0x04
#define X_EXISTING 0x08

অথবা

typedef enum { xNew = 1, xDeleted, xModified = 4, xExisting = 8 } RecordType;

অথবা

namespace RecordType {
    static const uint8 xNew = 1;
    static const uint8 xDeleted = 2;
    static const uint8 xModified = 4;
    static const uint8 xExisting = 8;
}

স্থানের প্রয়োজনীয়তাগুলি গুরুত্বপূর্ণ (বাইট বনাম int) তবে গুরুত্বপূর্ণ নয়। সংজ্ঞায়িত করে আমি টাইপ সুরক্ষা হারিয়েছি এবং এর সাথে enumআমি কিছু স্থান (পূর্ণসংখ্যার) হারাচ্ছি এবং সম্ভবত যখন আমি কিছুটা অপারেশন করতে চাই তখন নিক্ষেপ করতে হবে। সঙ্গে constআমি আমার মনে হয় আরো হারান টাইপ নিরাপত্তা যেহেতু একটি র্যান্ডম uint8ভুল করে পেতে পারে।

অন্য কোন পরিষ্কার উপায় আছে?

যদি তা না হয় তবে আপনি কী ব্যবহার করবেন এবং কেন?

পিএস বাকি কোডগুলি বরং আধুনিক সি ++ ছাড়াই পরিষ্কার #define, এবং আমি কয়েকটি স্পেসে নেমস্পেস এবং টেম্পলেট ব্যবহার করেছি, সুতরাং সেগুলিও প্রশ্নবিদ্ধ নয়।


"এনামের সাথে আমি কিছু স্থান (পূর্ণসংখ্যা) হারাতে চাই"। অগত্যা। দেখুন stackoverflow.com/questions/366017/... এবং stackoverflow.com/questions/1113855/... (এবং জিসিসি এর -fshort-enum আমি এই সি উত্তর এখনও সি সত্য ++, অভিমানী করছি
idbrii

@pydave আপনি যদি সি এবং সি ++ এর সামঞ্জস্যতা সম্পর্কে অনিশ্চিত হন তবে আমি এই লিঙ্কটি খুব সহায়ক বলে মনে করি, উদাহরণস্বরূপ enum david.tribble.com/text/cdiffs.htm#C99-enum-type
aka.nice

3
এটি উচ্চ ভোট সহ একটি পুরানো বিষয়, এই সমস্যার পরিস্থিতির জন্য সি ++ 11 এনাম ক্লাস না উল্লেখ করার কোনও কারণ আছে কি?
ব্র্যান্ডিন

একটি নোট হিসাবে, এর আকারের ছোট আকারের সাথে enum RecordType : uint8_tসুরক্ষার ধরনটি একত্রিত করে , যদিও আপনাকে এখনও বিটওয়াইজ অপারেটর সরবরাহ করতে হবে। enumuint8_t
জাস্টিন সময় - মনিকা 18

উত্তর:


88

একক পদ্ধতির অসুবিধা হ্রাস করার কৌশলগুলি একত্রিত করুন। আমি এম্বেড থাকা সিস্টেমে কাজ করি সুতরাং নিম্নলিখিত সমাধানটি পূর্ণসংখ্যক এবং বিটওয়াইজ অপারেটরগুলি দ্রুত, কম মেমরি এবং ফ্ল্যাশ ব্যবহারে কম তা এই সত্যের উপর ভিত্তি করে।

কনস্ট্যান্টদের বিশ্বব্যাপী নেমস্পেস দূষিত হওয়ার হাত থেকে বাঁচাতে একটি নেমস্পেসে এনাম রাখুন।

namespace RecordType {

একটি এনাম একটি টাইপিত টাইপিত সংকলন সময় ঘোষণা করে এবং সংজ্ঞা দেয়। যুক্তি এবং ভেরিয়েবলগুলি সঠিক ধরণের দেওয়া হয়েছে তা নিশ্চিত করার জন্য সর্বদা সংকলন টাইম টাইপ চেকিং ব্যবহার করুন। সি ++ তে টাইপডেফের দরকার নেই।

enum TRecordType { xNew = 1, xDeleted = 2, xModified = 4, xExisting = 8,

একটি অবৈধ রাষ্ট্রের জন্য অন্য সদস্য তৈরি করুন। এটি ত্রুটি কোড হিসাবে কার্যকর হতে পারে; উদাহরণস্বরূপ, আপনি যখন রাজ্যে ফিরে আসতে চান তবে আই / ও অপারেশন ব্যর্থ হয়। এটি ডিবাগিংয়ের জন্যও কার্যকর; ভেরিয়েবলের মান ব্যবহার করা উচিত কিনা তা জানতে এটি সূচনা তালিকা এবং ডেস্ট্রাক্টরগুলিতে ব্যবহার করুন।

xInvalid = 16 };

এই ধরণের জন্য আপনার দুটি উদ্দেশ্য রয়েছে তা বিবেচনা করুন। রেকর্ডের বর্তমান অবস্থার উপর নজর রাখতে এবং নির্দিষ্ট রাজ্যে রেকর্ড নির্বাচন করতে একটি মাস্ক তৈরি করতে। ধরণের মানটি আপনার উদ্দেশ্যে বৈধ কিনা তা পরীক্ষা করতে একটি ইনলাইন ফাংশন তৈরি করুন; একটি রাষ্ট্র চিহ্নিতকারী বনাম একটি রাজ্য মুখোশ হিসাবে। এটি ত্রুটিগুলি যেমন ধরা পড়বে তেমন typedefহ'ল এক intএবং মূল্য যেমন 0xDEADBEEFঅনির্বাচিত বা ভ্রান্ত পরিবর্তনশীলগুলির মাধ্যমে আপনার পরিবর্তনশীল হতে পারে।

inline bool IsValidState( TRecordType v) {
    switch(v) { case xNew: case xDeleted: case xModified: case xExisting: return true; }
    return false;
}

 inline bool IsValidMask( TRecordType v) {
    return v >= xNew  && v < xInvalid ;
}

usingআপনি যদি প্রায়ই টাইপটি ব্যবহার করতে চান তবে একটি নির্দেশিকা যুক্ত করুন ।

using RecordType ::TRecordType ;

মান পরীক্ষা করার ফাংশনগুলি ব্যবহারের সাথে সাথে খারাপ মানগুলিকে ফাঁদে ফেলাতে দৃ are়ভাবে কার্যকর হয়। দৌড়ানোর সময় আপনি যত দ্রুত বাগ ধরেন তত কম ক্ষতি এটি করতে পারে।

সব কিছু একসাথে রাখার জন্য এখানে কয়েকটি উদাহরণ দেওয়া হল।

void showRecords(TRecordType mask) {
    assert(RecordType::IsValidMask(mask));
    // do stuff;
}

void wombleRecord(TRecord rec, TRecordType state) {
    assert(RecordType::IsValidState(state));
    if (RecordType ::xNew) {
    // ...
} in runtime

TRecordType updateRecord(TRecord rec, TRecordType newstate) {
    assert(RecordType::IsValidState(newstate));
    //...
    if (! access_was_successful) return RecordType ::xInvalid;
    return newstate;
}

সঠিক মান সুরক্ষা নিশ্চিত করার একমাত্র উপায় হ'ল অপারেটর ওভারলোডগুলির সাথে একটি উত্সর্গীকৃত ক্লাস ব্যবহার করা এবং এটি অন্য পাঠকের জন্য অনুশীলন হিসাবে ছেড়ে দেওয়া হয়।


1
বেশিরভাগই একটি দুর্দান্ত উত্তর - তবে প্রশ্নটি এই বলে দেয় যে পতাকাগুলি একত্রিত করা যায় এবং ইসভালিস্টেট () ফাংশনটি তাদের একত্রিত হওয়ার অনুমতি দেয় না।
জোনাথন লেফলার

3
@ জোনাথন লেফলার: আমি যেখান থেকে দাঁড়িয়েছি বলে আমি মনে করি যে 'ইসভালিডস্টেট' এমনটি করার কথা নয়, 'ইসভালিডমাস্ক'।
জোও পোর্তেলা

1
এটি কি পছন্দসই যা IsValidMaskকোনও (যেমন 0) নির্বাচন করার অনুমতি দেয় না ?
জোছিম সৌর

2
−1 রানটাইম টাইপ চেকিংয়ের ধারণাটি একটি ঘৃণা।
চিয়ার্স এবং এইচটিএইচ - আলফ

54

সংজ্ঞাগুলি ভুলে যান

তারা আপনার কোডকে দূষিত করবে।

bitfields?

struct RecordFlag {
    unsigned isnew:1, isdeleted:1, ismodified:1, isexisting:1;
};

কখনও যে ব্যবহার করবেন না । 4 ইনটকে অর্থনৈতিক করার চেয়ে আপনি গতির সাথে বেশি চিন্তিত। বিট ক্ষেত্রগুলি ব্যবহার করা অন্য যে কোনও ধরণের অ্যাক্সেসের চেয়ে ধীর।

তবে স্ট্রটে বিট সদস্যদের ব্যবহারিক ঘাটতি রয়েছে। প্রথমত, মেমরিতে বিটের ক্রম সংকলক থেকে সংকলক পর্যন্ত পরিবর্তিত হয়। এছাড়াও, অনেক জনপ্রিয় সংকলক বিট সদস্যগুলি পড়ার জন্য এবং লেখার জন্য অযোগ্য কোড তৈরি করে এবং বিট ক্ষেত্রগুলি সম্পর্কিত বিশেষত গুরুতর থ্রেড সুরক্ষার সমস্যা রয়েছে (বিশেষত মাল্টিপ্রসেসর সিস্টেমগুলিতে) যে কারণে বেশিরভাগ মেশিনগুলি মেমরির বিটগুলির নির্বিচার সেটগুলি পরিচালনা করতে পারে না, তবে এর পরিবর্তে পুরো শব্দ লোড এবং সংরক্ষণ করতে হবে। যেমন নিঃশব্দ ব্যবহার না করেও নিম্নলিখিতটি থ্রেড-নিরাপদ হবে না

সূত্র: http://en.wikedia.org/wiki/Bit_field :

এবং যদি আপনার বিটফিল্ড না ব্যবহার করার আরও কারণ প্রয়োজন হয় তবে সম্ভবত রেমন্ড চেন আপনাকে তাঁর ওল্ড নিউ থিং পোস্টে বোঝাতে পারবেন : http://blogs.msdn.com/oldnewthing/বুলিয়ান সংগ্রহের জন্য বিটফিল্ডগুলির ব্যয়-বেনিফিট বিশ্লেষণ সংরক্ষণাগার / 2008/11/26 / 9143050.aspx

কনট ইনট?

namespace RecordType {
    static const uint8 xNew = 1;
    static const uint8 xDeleted = 2;
    static const uint8 xModified = 4;
    static const uint8 xExisting = 8;
}

এগুলিকে একটি নেমস্পেসে রাখা দুর্দান্ত। সেগুলি যদি আপনার সিপিপি বা শিরোলেখ ফাইলটিতে ঘোষণা করা হয় তবে তাদের মানগুলি ইনলাইন করা হবে। আপনি এই মানগুলিতে স্যুইচ ব্যবহার করতে সক্ষম হবেন তবে এটি মিলন সামান্য বাড়বে।

আহ, হ্যাঁ: স্থিতিশীল কীওয়ার্ডটি সরান । স্ট্যাটিকটি সি ++ এ হ্রাস করা হয় যখন আপনি যেমন ব্যবহার করেন এবং uint8 যদি বিল্টিন টাইপ হয় তবে একই মডিউলের একাধিক উত্স দ্বারা অন্তর্ভুক্ত শিরোনামে এটি প্রকাশ করার জন্য আপনার এটির প্রয়োজন হবে না। শেষ পর্যন্ত, কোডটি হওয়া উচিত:

namespace RecordType {
    const uint8 xNew = 1;
    const uint8 xDeleted = 2;
    const uint8 xModified = 4;
    const uint8 xExisting = 8;
}

এই পদ্ধতির সমস্যাটি হ'ল আপনার কোডটি আপনার ধ্রুবকের মান জানে যা সংযোজনকে কিছুটা বাড়ায়।

enum

কিছুটা শক্তিশালী টাইপিং সহ কনট ইন্ট হিসাবে একই।

typedef enum { xNew = 1, xDeleted, xModified = 4, xExisting = 8 } RecordType;

যদিও তারা এখনও বিশ্বব্যাপী নেমস্পেসকে দূষিত করছে। যাইহোক ... টাইপেডেফ সরান । আপনি সি ++ এ কাজ করছেন। এনাম এবং স্ট্রাক্টগুলির সেই টাইপিডগুলি কোডকে অন্য যে কোনও কিছুর চেয়ে বেশি দূষিত করছে।

ফলাফল কৃপা:

enum RecordType { xNew = 1, xDeleted, xModified = 4, xExisting = 8 } ;

void doSomething(RecordType p_eMyEnum)
{
   if(p_eMyEnum == xNew)
   {
       // etc.
   }
}

যেমন আপনি দেখতে পাচ্ছেন, আপনার এনাম বিশ্বব্যাপী নেমস্পেসকে দূষিত করছে। আপনি যদি এই এনামটিকে কোনও একটি নাম স্থানটিতে রাখেন তবে আপনার মতো কিছু থাকবে:

namespace RecordType {
   enum Value { xNew = 1, xDeleted, xModified = 4, xExisting = 8 } ;
}

void doSomething(RecordType::Value p_eMyEnum)
{
   if(p_eMyEnum == RecordType::xNew)
   {
       // etc.
   }
}

বাহ্যিক কনট ইনট?

আপনি যদি সংযুক্তিকে হ্রাস করতে চান (অর্থাত্ কনস্ট্যান্টগুলির মানগুলি আড়াল করতে সক্ষম হচ্ছেন এবং তাই, পুরো পুনঃসংশোধনের প্রয়োজন ছাড়াই তাদের পছন্দসই রূপান্তর করুন), আপনি শিরোনামের বাহ্যিক হিসাবে সিপিপি এবং সিপিপি ফাইলে স্থির হিসাবে ঘোষণা করতে পারেন , নিম্নলিখিত উদাহরণ হিসাবে:

// Header.hpp
namespace RecordType {
    extern const uint8 xNew ;
    extern const uint8 xDeleted ;
    extern const uint8 xModified ;
    extern const uint8 xExisting ;
}

এবং:

// Source.hpp
namespace RecordType {
    const uint8 xNew = 1;
    const uint8 xDeleted = 2;
    const uint8 xModified = 4;
    const uint8 xExisting = 8;
}

যদিও আপনি এই ধ্রুবকগুলিতে স্যুইচ ব্যবহার করতে সক্ষম হবেন না। সুতরাং শেষ পর্যন্ত, আপনার বিষ বাছুন ... :-p


5
আপনি কী মনে করেন বিটফিল্ডগুলি ধীর? আপনি কি কোডটি এবং এটি অন্য একটি পদ্ধতি ব্যবহার করে প্রকৃতপক্ষে প্রোফাইল করেছেন? যদি তা হয় তবে স্পষ্টতা গতির চেয়ে বেশি গুরুত্বপূর্ণ হতে পারে, "কখনও কখনও এটি ব্যবহার করবেন না" তৈরি করে কিছুটা সরল করে তোলা।
wnoise

"স্ট্যাটিক কনস্ট uint8 xNew;" কেবলমাত্র অপ্রয়োজনীয় কারণ সি ++ কনস্টের নেমস্পেস-স্কোপড ভেরিয়েবলগুলি অভ্যন্তরীণ সংযোগের জন্য ডিফল্ট। "কনস্ট্যান্ট" সরান এবং এটিতে বাহ্যিক সংযোগ রয়েছে। এছাড়াও, "এনাম {...} রেকর্ডটাইপ;" "রেকর্ডটাইপ" নামে একটি বিশ্বব্যাপী ভেরিয়েবল ঘোষণা করে যার প্রকার একটি বেনাম এনাম।
bk1e

ওয়ানবায়োন: প্রথমত, প্রধান কারণটি হ'ল লাভ (কিছু বাইট, যদি থাকে) লোকসানের দ্বারা উপচে পড়েছিল (অ্যাক্সেস করতে ধীর, উভয়ই পড়তে এবং লিখতে পারে) ...
প্যারাসেবল

3
ওয়ানবায়োন: দ্বিতীয়ত, আমি কর্মে বা বাড়িতে যে সমস্ত কোড উত্পন্ন করি সেগুলি সহজাতভাবে থ্রেড নিরাপদ। এটি করা সহজ: কোনও গ্লোবাল, কোনও স্ট্যাটিক, লক-সুরক্ষিত না হলে থ্রেডগুলির মধ্যে ভাগ করা যায় না। এই আইডিয়মটি ব্যবহার করা এই প্রাথমিক থ্রেড-সুরক্ষাটি ভেঙে দেবে। এবং কি জন্য? কয়েকটি বাইট সম্ভবত ? ... :-) ...
প্যারাসবেল

বিটফিল্ডের লুকানো খরচের বিষয়ে রেমন্ড চেনের নিবন্ধে যোগ করা রেফারেন্স।
পেরেসারবাল

30

আপনি কি স্ট্যান্ড :: বিটসেটকে বাতিল করেছেন? পতাকাগুলির সেটগুলি এটির জন্য। ডু

typedef std::bitset<4> RecordType;

তারপর

static const RecordType xNew(1);
static const RecordType xDeleted(2);
static const RecordType xModified(4);
static const RecordType xExisting(8);

কারণ বিটসেটের জন্য প্রচুর অপারেটর ওভারলোড রয়েছে, আপনি এখন এটি করতে পারেন

RecordType rt = whatever;      // unsigned long or RecordType expression
rt |= xNew;                    // set 
rt &= ~xDeleted;               // clear 
if ((rt & xModified) != 0) ... // test

বা এর সাথে খুব সাদৃশ্যপূর্ণ কিছু - আমি যেহেতু এটি পরীক্ষা না করে আমি কোনও সংশোধনীর প্রশংসা করব। আপনি সূচক দ্বারা বিটগুলিও উল্লেখ করতে পারেন, তবে কেবলমাত্র এক সেট ধ্রুবককে সংজ্ঞায়িত করা ভাল এবং রেকর্ডটাইপ ধ্রুবকগুলি সম্ভবত আরও দরকারী।

ধরি আপনি bitset ছিটকে থাকে, তবে আমি ভোট enum

আমি কিনেছি না যে এনামগুলিকে aালাই মারাত্মক অসুবিধা - ঠিক আছে তাই এটি কিছুটা গোলমাল, এবং একটি এনামকে একটি বহিরাগত মান নির্ধারণ করা অপরিজ্ঞাত আচরণ, সুতরাং তাত্ত্বিকভাবে কিছু অস্বাভাবিক সি ++ এর উপর পায়ে গুলি করা তাত্ত্বিকভাবে সম্ভব possible বাস্তবায়নের। তবে আপনি যদি এটি প্রয়োজন কেবল তখনই করেন (যা অন্তর্নিহিত থেকে এনাম আইরিকে যাওয়ার সময় হয়), এটি পুরোপুরি স্বাভাবিক কোড যা লোকেরা আগে দেখেছিল।

আমি এনামের যে কোনও স্থান ব্যয় সম্পর্কেও সন্দেহজনক। uint8 ভেরিয়েবল এবং প্যারামিটারগুলি সম্ভবত ints এর চেয়ে কম স্ট্যাক ব্যবহার করবে না, তাই কেবলমাত্র ক্লাসের ক্ষেত্রে স্টোরেজ। কিছু ক্ষেত্রে রয়েছে যেখানে স্ট্রাক্টে একাধিক বাইট প্যাকিং জিতে যাবে (এক্ষেত্রে আপনি uint8 স্টোরেজে এনামগুলিকে কাস্ট করতে পারেন) তবে সাধারণত প্যাডিং কোনওভাবেই সুবিধাটি হারাবে।

সুতরাং এনামগুলির সাথে অন্যগুলির সাথে তুলনা করার কোনও অসুবিধা নেই এবং একটি সুবিধা হিসাবে আপনাকে কিছুটা ধরণের সুরক্ষা দেয় (আপনি স্পষ্টভাবে কাস্টিং ব্যতীত কিছু এলোমেলো পূর্ণসংখ্যার মান নির্ধারণ করতে পারবেন না) এবং সমস্ত কিছু উল্লেখ করার পরিষ্কার উপায়।

পছন্দের জন্য আমি এনামে "= 2" রাখতাম। এটি প্রয়োজনীয় নয়, তবে একটি "অন্তত বিস্ময়ের নীতি" পরামর্শ দেয় যে সমস্ত 4 সংজ্ঞা একইরকম দেখা উচিত।


1
আসলে, আমি মোটেই বিটসেট বিবেচনা করি নি। তবে আমি নিশ্চিত না যে এটি ভাল হবে। বিটসেটের সাথে, আমাকে বিটগুলি 1, 2, 3, 4 হিসাবে সম্বোধন করতে হবে যা কোড কম পাঠযোগ্য হবে - যার অর্থ আমি সম্ভবত বিটগুলির নাম 'নামকরণ করতে একটি এনাম ব্যবহার করব। যদিও স্পেস সেভার হতে পারে। ধন্যবাদ।
মিলান বাবুস্কভ

মিলান, আপনাকে এনাম ব্যবহার করে বিটগুলি "নাম" দিতে হবে না, আপনি উপরে বর্ণিত পূর্বনির্ধারিত বিটগুলি ব্যবহার করতে পারেন। আপনি যদি আমার_বিটসেট.ফ্লিপ (1) এর পরিবর্তে বিট একটি চালু করতে চান তবে আপনি আমার_বিটসেটটি করতে হবে | = x নতুন;
শে

এটি আপনার দিকে কম এবং এসটিএলে আরও নির্দেশিত, তবে: আমাকে সত্যিই জিজ্ঞাসা করতে হবে: আপনি কেন এটির bitsetজন্য ব্যবহার করবেন? এটি সাধারণত longএকটিতে অনুবাদ হয় (আমার বাস্তবায়নে আইর্সে; হ্যাঁ, কতটা অপব্যয়যুক্ত) বা যাইহোক যাইহোক প্রতিটি উপাদানগুলির জন্য একই জাতীয় ইন্টিগ্রাল টাইপ, তবে কেন কেবল অবিচ্ছিন্ন ইন্টিগ্রাল ব্যবহার করবেন না? (বা, আজকাল, constexprশূন্য সঞ্চয় সহ)
আন্ডারস্কোর_২০

[টাইমআউট সম্পাদনা করুন] ... তবে তারপরে আমি bitsetক্লাসের যৌক্তিকতাটি সত্যই বুঝতে পারি নি , 'উ'র চারপাশের আলোচনার ক্ষেত্রে বারবার অন্তর্নিহিত বলে মনে করা ছাড়া, আমাদের অবশ্যই ভাষার অযৌক্তিক নিম্ন-স্তরের শিকড় আবরণ করতে হবে '
আন্ডারস্কোর_ডি

" uint8ভেরিয়েবল এবং প্যারামিটারগুলি সম্ভবত কোনও কম স্ট্যাক ব্যবহার করবে না ints" ভুল। আপনার যদি 8-বিট রেজিস্টারগুলির একটি সিপিইউ থাকে, intতবে কমপক্ষে 2 টি রেজিস্টার uint8_tপ্রয়োজন যেখানে কেবলমাত্র 1 প্রয়োজন, তাই আপনার আরও স্ট্যাক স্পেসের প্রয়োজন হবে কারণ আপনি নিবন্ধের বাইরে চলে যাওয়ার সম্ভাবনা বেশি (এটি ধীরতর এবং কোডের আকার বৃদ্ধি করতে পারে) ( নির্দেশ সেট উপর নির্ভর করে))। (আপনার টাইপ রয়েছে, এটি হওয়া উচিত uint8_tনয় uint8)
12431234123412341234123

8

এখানে কনস্ট বনাম ম্যাক্রো বনাম এনামগুলি সম্পর্কিত কয়েকটি নিবন্ধ রয়েছে:

সিম্বলিক কনস্ট্যান্টস
এনুমারেশন কনস্ট্যান্ট বনাম কনস্ট্যান্ট অবজেক্টস

আমি মনে করি আপনার ম্যাক্রোগগুলি এড়ানো উচিত বিশেষত যেহেতু আপনি লিখেছেন আপনার বেশিরভাগ নতুন কোড আধুনিক সি ++ তে রয়েছে।


5

সম্ভব হলে ম্যাক্রো ব্যবহার করবেন না। আধুনিক সি ++ এর ক্ষেত্রে এগুলি খুব বেশি প্রশংসিত হয় না।


4
সত্য। আমি ম্যাক্রো সম্পর্কে যা ঘৃণা করি তা হ'ল তারা যদি ভুল হয় তবে আপনি সেগুলির মধ্যে পদক্ষেপ নিতে পারবেন না।
কার্ল

আমি ধারণা করি যে এটি এমন কিছু যা সংকলকটিতে স্থির করা যেতে পারে।
সেল্টিকিমিনস্ট্রেল

4

এনামগুলি আরও উপযুক্ত হবে কারণ তারা "শনাক্তকারীদের অর্থ" দেওয়ার পাশাপাশি সুরক্ষা টাইপ করে। আপনি পরিষ্কারভাবে বলতে পারবেন যে "xDeleted" "রেকর্ডটাইপ" এর এবং এটি বছরের পরও "রেকর্ডের ধরণ" (বাহ!) উপস্থাপন করে। কনটসগুলির জন্য মন্তব্যগুলির প্রয়োজন হবে, এছাড়াও তাদের কোডে উপরে এবং নীচে যেতে হবে।


4

সংজ্ঞায়িত করে আমি টাইপ সুরক্ষা হারাতে চাই

অগত্যা ...

// signed defines
#define X_NEW      0x01u
#define X_NEW      (unsigned(0x01))  // if you find this more readable...

এবং এনামের সাথে আমি কিছু স্থান হ'ল (পূর্ণসংখ্যা)

অগত্যা নয় - তবে আপনার স্টোরেজ পয়েন্টগুলিতে স্পষ্ট হতে হবে ...

struct X
{
    RecordType recordType : 4;  // use exactly 4 bits...
    RecordType recordType2 : 4;  // use another 4 bits, typically in the same byte
    // of course, the overall record size may still be padded...
};

এবং যখন আমি বিটওয়াইজ অপারেশন করতে চাই তখন সম্ভবত কাস্ট করতে হবে।

এর থেকে যন্ত্রণা বের করতে আপনি অপারেটর তৈরি করতে পারেন:

RecordType operator|(RecordType lhs, RecordType rhs)
{
    return RecordType((unsigned)lhs | (unsigned)rhs);
}

কনস্টের সাথে আমার মনে হয় যে আমি এ জাতীয় সুরক্ষাও হারিয়েছি যেহেতু এলোমেলোভাবে uint8 ভুল করে প্রবেশ করতে পারে।

এই যেকোনও পদ্ধতির সাথে একই ঘটতে পারে: পরিসীমা এবং মান চেকগুলি সাধারণত সুরক্ষা টাইপ করার জন্য অরথোগোনাল হয় (যদিও ব্যবহারকারী-সংজ্ঞায়িত প্রকারগুলি - যেমন আপনার নিজস্ব শ্রেণি - তাদের ডেটা সম্পর্কে "আক্রমণকারী" প্রয়োগ করতে পারে)। এনামগুলির সাথে, সংকলকটি মানগুলি হোস্ট করার জন্য আরও বড় ধরণের বাছাই করতে পারে এবং অবিচ্ছিন্ন, দূষিত বা মিস-মিস এনাম ভেরিয়েবলটি এখনও তার বিট প্যাটার্নটি এমন একটি সংখ্যা হিসাবে ব্যাখ্যা করতে পারে যা আপনি প্রত্যাশা করেননি - যে কোনওটির সাথে অসম তুলনা করে could গণনা শনাক্তকারী, তাদের যে কোনও সংমিশ্রণ এবং 0।

অন্য কোন পরিষ্কার উপায় আছে? / যদি না হয়, আপনি কি ব্যবহার করবেন এবং কেন?

ঠিক আছে, শেষ পর্যন্ত চেষ্টা করা-বিশ্বাসযোগ্য সি-স্টাইলের বিটওয়াইস বা অঙ্কেরগুলি আপনার ছবিতে বিট ফিল্ড এবং কাস্টম অপারেটরগুলির পরে বেশ ভালভাবে কাজ করে। আপনি আরও কিছু কাস্টম বৈধতা কার্যকারিতা এবং ম্যাট_জেকের উত্তরের মত হিসাবে দৃ rob়তা আরও উন্নত করতে পারেন; কৌশলগুলি হ্যান্ডলিং স্ট্রিং, ইনট, ডাবল মান ইত্যাদি ক্ষেত্রে প্রায়শই সমানভাবে প্রযোজ্য ..

আপনি যুক্তি দিতে পারেন যে এটি "ক্লিনার":

enum RecordType { New, Deleted, Modified, Existing };

showRecords([](RecordType r) { return r == New || r == Deleted; });

আমি উদাসীন: ডেটা বিটস প্যাক শক্ততর তবে কোডটি উল্লেখযোগ্যভাবে বৃদ্ধি পেয়েছে ... আপনি কতগুলি জিনিস পেয়েছেন তা নির্ভর করে এবং লামডাবাস - তারা যেমন সুন্দর - তবুও বিটওয়াইস ওআরএসের চেয়ে ডান পেতে আরও মেসওয়্যার এবং শক্ত।

বিটিডাব্লু / - থ্রেড সুরক্ষার বেশ দুর্বল আইএমএইচও সম্পর্কে যুক্তি - একটি প্রভাবশালী সিদ্ধান্ত-চালিকা শক্তি হওয়ার চেয়ে পটভূমি বিবেচনা হিসাবে সেরা স্মরণ করা হয়; বিটফিল্ডগুলি জুড়ে একটি মিটেক্স ভাগ করা আরও সম্ভবত অনুশীলন যা তাদের প্যাকিং সম্পর্কে অজানা থাকলেও (মুটেক্সগুলি তুলনামূলকভাবে বড় ডেটা সদস্য হয় - একটি অবজেক্টের সদস্যদের একাধিক মিউটেক্স রাখার বিষয়ে বিবেচনা করার জন্য আমাকে কার্য সম্পাদনের বিষয়ে সত্যই উদ্বিগ্ন হতে হবে এবং আমি মনোযোগ সহকারে তাকাব তারা বিট ক্ষেত্র ছিল লক্ষ্য করার জন্য যথেষ্ট)। যে কোনও সাব-ওয়ার্ড-আকারের ধরণের ক্ষেত্রে একই সমস্যা হতে পারে (উদাঃ ক uint8_t)। যাইহোক, আপনি যদি উচ্চতর সম্মতিতে মরিয়া হন তবে আপনি পারমাণবিক তুলনা-ও-স্বাপ শৈলী ক্রিয়াকলাপ চেষ্টা করতে পারেন।


1
ভাল +1। তবে নির্দেশের আগে operator|একটি পূর্ণসংখ্যা টাইপ ( unsigned int) এ কাস্ট করা উচিত |। অন্যটি operator|পুনরাবৃত্তভাবে নিজেকে কল করবে এবং রান-টাইম স্ট্যাকের ওভারফ্লো করবে। আমি আপনাকে পরামর্শ দিচ্ছি: return RecordType( unsigned(lhs) | unsigned(rhs) );। চিয়ার্স
ওলিব্রে

3

এমনকি যদি আপনাকে এনাম সংরক্ষণ করতে 4 বাইট ব্যবহার করতে হয় (আমি সি ++ এর সাথে তেমন পরিচিত নই - আমি জানি আপনি সি # তে অন্তর্নিহিত ধরণটি নির্দিষ্ট করতে পারেন) তবে এটি এখনও মূল্যবান - এনামগুলি ব্যবহার করুন।

জিবিএস মেমরির সাথে এই দিন এবং সার্ভারের যুগে সাধারণত অ্যাপ্লিকেশন স্তরে 4 বাইট বনাম 1 মেমরির বাইটের মতো জিনিস বিবেচনা করে না। অবশ্যই, যদি আপনার বিশেষ পরিস্থিতিতে মেমরির ব্যবহারটি গুরুত্বপূর্ণ (এবং আপনি এনামকে ব্যাক করতে বাইট ব্যবহার করতে সি ++ পেতে পারেন না) তবে আপনি 'স্ট্যাটিক কনস্ট' রুটটি বিবেচনা করতে পারেন।

দিনের শেষে, আপনাকে নিজেকে জিজ্ঞাসা করতে হবে, আপনার ডেটা স্ট্রাকচারের জন্য 3 বাইটের মেমরি সঞ্চয় করার জন্য 'স্ট্যাটিক কনস্ট' ব্যবহারের রক্ষণাবেক্ষণের মূল্যটি কী উপযুক্ত?

অন্য কিছু মনে রাখতে হবে - আইআইআরসি, x86-এ, ডেটা স্ট্রাকচারগুলি 4-বাইট প্রান্তিককরণ করা হয়, সুতরাং আপনার 'রেকর্ড' কাঠামোর মধ্যে বাইট-প্রস্থের বেশ কয়েকটি উপাদান না থাকলে এটি আসলে গুরুত্বপূর্ণ নয়। পারফরম্যান্স / স্পেসের জন্য রক্ষণাবেক্ষণে ট্রেডঅফ করার আগে এটি পরীক্ষা করে নিন এবং নিশ্চিত করুন।


ভাষা রিভিশন সি ++ 11 হিসাবে আপনি সি ++ তে অন্তর্নিহিত ধরণটি নির্দিষ্ট করতে পারেন। ততদিন পর্যন্ত, আমি বিশ্বাস করি যে এটি "নির্দিষ্ট করে দেওয়া সমস্ত গণকের জন্য যথেষ্ট পরিমাণে সঞ্চয় এবং বিট ক্ষেত্র হিসাবে ব্যবহৃত হতে পারে, তবে সম্ভবত intএটি খুব ছোট না হলে"। [আপনি যদি C ++ 11 এ অন্তর্নিহিত ধরণটি নির্দিষ্ট না করেন তবে এটি উত্তরাধিকার আচরণ ব্যবহার করে। বিপরীতে, সি ++ 11 enum classএর অন্তর্নিহিত প্রকারটি intঅন্যথায় নির্দিষ্ট না হলে স্পষ্টতই ডিফল্ট হয় ]]
জাস্টিন সময় - মনিকা পুনরায়

3

যদি আপনি অঙ্কের বাক্য গঠন এবং বিট পরীক্ষার সুবিধার সাথে ক্লাসগুলির প্রকার সুরক্ষা চান তবে সি ++ এ নিরাপদ লেবেল বিবেচনা করুন । আমি লেখকের সাথে কাজ করেছি, এবং তিনি বেশ স্মার্ট।

সাবধান, যদিও। শেষ পর্যন্ত, এই প্যাকেজটি টেমপ্লেট এবং ম্যাক্রো ব্যবহার করে!


আমার ছোট অ্যাপটির জন্য ওভারকিলের মতো দেখাচ্ছে। তবে এটি একটি ভাল সমাধান বলে মনে হচ্ছে।
মিলান বাবুস্কভ

2

আপনার কি আসলে ধারণাগত সামগ্রিক হিসাবে পতাকাটির মানগুলি অতিক্রম করতে হবে, বা আপনার কাছে প্রতি পতাকা পতাকা কোড রয়েছে? যেভাবেই হোক না কেন, আমি মনে করি এটি 1-বিট বিটফিল্ডগুলির শ্রেণি বা কাঠামো হিসাবে থাকা আসলে সম্ভবত পরিষ্কার হতে পারে:

struct RecordFlag {
    unsigned isnew:1, isdeleted:1, ismodified:1, isexisting:1;
};

তারপরে আপনার রেকর্ড শ্রেণিতে স্ট্রাক্ট রেকর্ডফ্লাগের সদস্যের পরিবর্তনশীল থাকতে পারে, ফাংশনগুলি স্ট্রাক্ট রেকর্ডফ্লেগ ইত্যাদির আর্গুমেন্ট নিতে পারে etc.


কখনও পুরো হিসাবে, কখনও পতাকা হিসাবে। এবং, আমারও পরীক্ষা করা দরকার যদি একটি নির্দিষ্ট পতাকা সেট করা থাকে (যখন আমি এটি পুরোপুরি পাস করি)।
মিলান বাবুস্কভ

ভাল, যখন পৃথক, শুধু একটি int জিজ্ঞাসা করুন। যখন একসাথে, স্ট্রাক পাস।
wnoise

এটা ভাল হবে না। বিট ক্ষেত্রগুলিতে অ্যাক্সেস অন্য কোনও কিছুর চেয়ে ধীর।
প্যারাসেবল

সত্যি? আপনি কি মনে করেন যে সংকলকটি ম্যানুয়াল বিট-টুইডলিংয়ের চেয়ে বিট-ফিল্ডগুলি পরীক্ষার জন্য উল্লেখযোগ্যভাবে আলাদা কোড তৈরি করবে? এবং এটি উল্লেখযোগ্যভাবে ধীর হবে? কেন? আপনি যে বিষয়টি খুব সহজে ইচ্ছে করে করতে পারবেন না তা হ'ল একসাথে একাধিক পতাকা।
wnoise

একটি সহজ পড়ার পরীক্ষা চালিয়ে আমি বিট-ফিল্ড অ্যাক্সেসের জন্য 5.45-5.59 বনাম বিট-মাস্কিংয়ের জন্য 5.50-5.58 সেকেন্ড পাই। বেশ অনেকটা পার্থক্যহীন।
Wnoise

2

আমি সম্ভবত এই জাতীয় কোনও জিনিসের জন্য এনাম ব্যবহার করব না যেখানে মানগুলি একত্রিত করা যায়, সাধারণত এনামগুলি পারস্পরিক একচেটিয়া রাজ্য হয়।

তবে আপনি যে কোনও পদ্ধতি ব্যবহার করুন, এটি আরও পরিষ্কার করে তুলতে যে এগুলি মানগুলি যা বিটগুলি একত্রিত হতে পারে, পরিবর্তে প্রকৃত মানগুলির জন্য এই বাক্য গঠনটি ব্যবহার করুন:

#define X_NEW      (1 << 0)
#define X_DELETED  (1 << 1)
#define X_MODIFIED (1 << 2)
#define X_EXISTING (1 << 3)

সেখানে বাম-শিফট ব্যবহার করে এটি নির্দেশ করতে সহায়তা করে যে প্রতিটি মান একক বিট হিসাবে চিহ্নিত করা হয়, এটি সম্ভবত কমই হয় যে পরে কেউ নতুন কিছু যুক্ত করার মতো কিছু ভুল করে এবং এটির 9 এর মান নির্ধারণ করে।


1
এর জন্য যথেষ্ট নজির রয়েছে, বিশেষত আইওএসটিএল () এর ধ্রুবকগুলিতে। আমি হেক্স কনস্ট্যান্ট ব্যবহার করতে পছন্দ করি, যদিও: 0x01, 0x02, 0x04, 0x08, 0x10, ...
জোনাথন লেফলার

2

কেআইএসএস , উচ্চ সংহতি এবং নিম্ন মিলনের উপর ভিত্তি করে এই প্রশ্নগুলি জিজ্ঞাসা করুন -

  • কার জানা দরকার? আমার ক্লাস, আমার গ্রন্থাগার, অন্যান্য ক্লাস, অন্যান্য গ্রন্থাগার, 3 য় পক্ষ
  • আমার কী স্তরের বিমূর্ততা সরবরাহ করতে হবে? গ্রাহক কি বিট ক্রিয়াকলাপ বোঝে?
  • আমার কি ভিবি / সি # ইত্যাদি থেকে ইন্টারফেস করতে হবে?

একটি দুর্দান্ত বই রয়েছে " লার্জ-স্কেল সি ++ সফটওয়্যার ডিজাইন ", এটি বাহ্যিকভাবে বেস প্রকারগুলি প্রচার করে, আপনি যদি অন্য কোনও হেডার ফাইল / ইন্টারফেস নির্ভরতা এড়াতে পারেন তবে আপনার চেষ্টা করা উচিত।


1
ক) 5-6 ক্লাস। খ) কেবলমাত্র আমি, এটি একটি
একমানের

2

আপনি কিউটি ব্যবহার করছেন যদি আপনার কিউএফ্ল্যাগগুলি দেখতে হবে । কিউফ্ল্যাজ ক্লাস এনাম মানগুলির ওআর-সংমিশ্রণগুলি সংরক্ষণ করার জন্য টাইপ-নিরাপদ উপায় সরবরাহ করে।


না, কোন কিউ। আসলে, এটি একটি ডাব্লুএক্সউইজেডস প্রকল্প।
মিলান বাবুস্কভ

0

আমি বরং সাথে যেতে চাই

typedef enum { xNew = 1, xDeleted, xModified = 4, xExisting = 8 } RecordType;

কেবল কারণ:

  1. এটি ক্লিনার এবং এটি কোডটি পঠনযোগ্য এবং রক্ষণাবেক্ষণযোগ্য করে তোলে।
  2. এটি যৌক্তিকভাবে ধ্রুবককে দলবদ্ধ করে।
  3. প্রোগ্রামারটির সময়টি আরও গুরুত্বপূর্ণ, যদি না আপনার কাজ সেই 3 বাইট সংরক্ষণ করা হয়।

ভাল, আমি সহজেই ক্লাস রেকর্ডের এক মিলিয়ন উদাহরণ থাকতে পারি, তাই এটি গুরুত্বপূর্ণ হতে পারে। ওটো, এটি 1MB এবং 4MB এর মধ্যে কেবল একটি পার্থক্য, তাই সম্ভবত আমার চিন্তা করা উচিত নয়।
মিলান বাবুস্কভ

@ বিবেক: আপনি কি পূর্ণসংখ্যার প্রস্থের সীমাবদ্ধতা বিবেচনা করেছেন? বিশেষত সি ++ 11 এর আগে।
ব্যবহারকারী2672165

0

আমি সব কিছুর প্রকৌশলী করতে চাই না তবে কখনও কখনও এই ক্ষেত্রে এই তথ্যটি সজ্জিত করার জন্য একটি (ছোট) শ্রেণি তৈরি করা উপযুক্ত হতে পারে। আপনি যদি ক্লাস রেকর্ডটাইপ তৈরি করেন তবে এর এতে ফাংশন থাকতে পারে:

অকার্যকর সেট মুছে ফেলা ();

অকার্যকর ClearDeleted ();

bool isDeleted ();

ইত্যাদি ... (বা কনভেনশন অনুসারে যাই হোক না কেন)

এটি সংমিশ্রণগুলি বৈধ করতে পারে (এমন ক্ষেত্রে যেখানে সমস্ত সংমিশ্রণগুলি বৈধ নয়, যেমন 'নতুন' এবং 'মুছে ফেলা' উভয় একই সময়ে সেট করা যায় না)। আপনি যদি কেবল বিট মাস্কস ইত্যাদি ব্যবহার করেন তবে রাষ্ট্রটি যে কোডটি যাচাই করতে হবে সেট করে সেটি একটি শ্রেণি সেই যুক্তিকেও encapsulate করতে পারে।

শ্রেণিটি আপনাকে প্রতিটি রাজ্যে অর্থবহ লগিংয়ের তথ্য সংযুক্ত করার ক্ষমতাও দিতে পারে, আপনি বর্তমান রাষ্ট্রের স্ট্রিং উপস্থাপনা ইত্যাদি ফিরিয়ে আনতে কোনও ফাংশন যুক্ত করতে পারেন ইত্যাদি (বা স্ট্রিমিং অপারেটরগুলি << 'ব্যবহার করতে পারেন)।

সর্বোপরি যদি আপনি স্টোরেজ সম্পর্কে উদ্বিগ্ন থাকেন তবে আপনার ক্লাসে কেবলমাত্র 'চর' ডেটা সদস্য থাকতে পারে, তাই কেবলমাত্র অল্প পরিমাণে সঞ্চয়স্থান নেওয়া (এটি অনুমান করে যে এটি ভার্চুয়াল নয়)। অবশ্যই হার্ডওয়্যার ইত্যাদির উপর নির্ভর করে আপনার প্রান্তিককরণের সমস্যা থাকতে পারে।

আপনার যদি আসল বিট মানগুলি শিরোনাম ফাইলের পরিবর্তে সিপিপি ফাইলের ভিতরে কোনও বেনামে নেমস্পেসে থাকে তবে বাকী 'বিশ্বের' কাছে দৃশ্যমান নয়।

আপনি যদি দেখতে পান যে এনাম / # ডিফাইন / বিটমাস্ক ইত্যাদি ব্যবহার করে কোডটিতে অবৈধ সংমিশ্রণ, লগিং ইত্যাদির মোকাবেলায় প্রচুর 'সমর্থন' কোড রয়েছে তবে কোনও শ্রেণিতে এনক্যাপসুলেশন বিবেচনার জন্য উপযুক্ত হতে পারে। অবশ্যই বেশিরভাগ সময় সাধারণ সমস্যাগুলি সহজ সমাধানগুলি দিয়ে আরও ভাল হয় ...


দুর্ভাগ্যক্রমে, ঘোষণাটি একটি .h ফাইলে থাকতে হবে যেহেতু এটি প্রকল্প জুড়ে ব্যবহৃত হয় (প্রায় 5-6 শ্রেণি দ্বারা ব্যবহৃত হয়)।
মিলান বাবুস্কোভ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.