অনেক বেশি দাবী লেখা সম্ভব?
ঠিক আছে, অবশ্যই। [এখানে দুর্ভাগ্যজনক উদাহরণটি কল্পনা করুন]] তবে নীচে বর্ণিত গাইডলাইনগুলি প্রয়োগ করে, আপনাকে এই সীমাটি অনুশীলনে চালিত করতে সমস্যা হওয়া উচিত নয়। আমিও দৃser়তার একটি বড় অনুরাগী এবং আমি এই নীতিগুলি অনুসারে ব্যবহার করি। এই পরামর্শের বেশিরভাগই দৃser়তার সাথে বিশেষ নয় তবে কেবলমাত্র সাধারণ ভাল প্রকৌশল অনুশীলন তাদের জন্য প্রয়োগ করা হয়েছে।
রান-টাইম এবং বাইনারি পদচিহ্নগুলি মাথায় রাখুন
জোর দেওয়া দুর্দান্ত, তবে তারা যদি আপনার প্রোগ্রামটিকে অগ্রহণযোগ্যভাবে ধীর করে তোলে তবে তা হয় খুব বিরক্তিকর হবে অথবা আপনি তাড়াতাড়ি বা পরে এগুলি বন্ধ করে দেবেন।
এতে থাকা ফাংশনের ব্যয়ের তুলনায় আমি একটি দৃ of় মূল্য নির্ধারণ করতে চাই the নীচের দুটি উদাহরণ বিবেচনা করুন।
// Precondition: queue is not empty
// Invariant: queue is sorted
template <typename T>
const T&
sorted_queue<T>::max() const noexcept
{
assert(!this->data_.empty());
assert(std::is_sorted(std::cbegin(this->data_), std::cend(this->data_)));
return this->data_.back();
}
ফাংশন নিজেই একটি হল হে (1) অপারেশন কিন্তু গবেষকেরা হিসাব হে ( ঢ ) ওভারহেড। আমি মনে করি না যে খুব বিশেষ পরিস্থিতিতে না হলে আপনি এই ধরনের চেকগুলি সক্রিয় রাখতে চান।
এখানে অনুরূপ দৃser়তা সহ আরও একটি ফাংশন।
// Requirement: op : T -> T is monotonic [ie x <= y implies op(x) <= op(y)]
// Invariant: queue is sorted
// Postcondition: each item x in the queue is replaced by op(x)
template <typename T>
template <typename FuncT>
void
sorted_queue<T>::apply_monotonic_function(FuncT&& op)
{
assert(std::is_sorted(std::cbegin(this->data_), std::cend(this->data_)));
std::transform(std::cbegin(this->data_), std::cend(this->data_),
std::begin(this->data_), std::forward<FuncT>(op));
assert(std::is_sorted(std::cbegin(this->data_), std::cend(this->data_)));
}
ফাংশনটি নিজেই একটি হে ( এন ) অপারেশন তাই এটি দৃ for়তার জন্য অতিরিক্ত ও ( এন ) ওভারহেড যুক্ত করতে খুব কম ব্যথা করে। একটি ছোট দ্বারা একটি ফাংশন ধীরে ধীরে (এই ক্ষেত্রে, সম্ভবত 3 এরও কম) ধ্রুবক ফ্যাক্টর এমন একটি জিনিস যা আমরা সাধারণত একটি ডিবাগ বিল্ডে বহন করতে পারি তবে সম্ভবত রিলিজ বিল্ডে নয়।
এখন এই উদাহরণ বিবেচনা করুন।
// Precondition: queue is not empty
// Invariant: queue is sorted
// Postcondition: last element is removed from queue
template <typename T>
void
sorted_queue<T>::pop_back() noexcept
{
assert(!this->data_.empty());
return this->data_.pop_back();
}
যদিও পূর্বের উদাহরণে দুটি ও ( এন ) দৃser ়তার তুলনায় অনেক লোক সম্ভবত এই ও (1) জোর দিয়ে অনেক বেশি স্বাচ্ছন্দ্য বোধ করবেন , তারা আমার মতে নৈতিকভাবে সমান। প্রতিটি ফাংশন নিজেই জটিলতার ক্রমে ওভারহেড যুক্ত করে।
অবশেষে, "সত্যিই সস্তা" জোর রয়েছে যেগুলি যে ফাংশনটিতে অন্তর্ভুক্ত রয়েছে তার জটিলতায় আধিপত্য বজায় রয়েছে।
// Requirement: cmp : T x T -> bool is a strict weak ordering
// Precondition: queue is not empty
// Postcondition: if x is returned, then there is no y in the queue
// such that cmp(x, y)
template <typename T>
template <typename CmpT>
const T&
sorted_queue<T>::max(CmpT&& cmp) const
{
assert(!this->data_.empty());
const auto pos = std::max_element(std::cbegin(this->data_),
std::cend(this->data_),
std::forward<CmpT>(cmp));
assert(pos != std::cend(this->data_));
return *pos;
}
এখানে, আমাদের একটি ও ( এন ) ফাংশনে দুটি ও (1) জরিমানা রয়েছে । এমনকি রিলিজ বিল্ডগুলিতেও এই ওভারহেডটি রাখা সমস্যা হবে না।
তবে মনে রাখবেন যে অ্যাসিম্পটোটিক জটিলতাগুলি সর্বদা পর্যাপ্ত অনুমান দেয় না কারণ বাস্তবে আমরা "বিগ- ও " দ্বারা আচ্ছাদিত কিছু সীমাবদ্ধ এবং ধ্রুবক কারণগুলির দ্বারা আবদ্ধ ইনপুট মাপগুলি নিয়ে কাজ করি যা সম্ভবত খুব কমই তুচ্ছ নয়।
সুতরাং এখন আমরা বিভিন্ন পরিস্থিতিতে চিহ্নিত করেছি, সেগুলি সম্পর্কে আমরা কী করতে পারি? একটি (সম্ভবত খুব) সহজ পদ্ধতির একটি নিয়ম অনুসরণ করা হবে যেমন "তারা যে ফাংশনগুলিতে অন্তর্ভুক্ত রয়েছে তার উপর প্রভাব ফেলবে এমন দাবী ব্যবহার করবেন না।" যদিও এটি কিছু প্রকল্পের জন্য কাজ করতে পারে, অন্যদের আরও বেশি স্বতন্ত্র পদ্ধতির প্রয়োজন হতে পারে। এটি বিভিন্ন ক্ষেত্রে বিভিন্ন দৃser় ম্যাক্রো ব্যবহার করে করা যেতে পারে।
#define MY_ASSERT_IMPL(COST, CONDITION) \
( \
( ((COST) <= (MY_ASSERT_COST_LIMIT)) && !(CONDITION) ) \
? ::my::assertion_failed(__FILE__, __LINE__, __FUNCTION__, # CONDITION) \
: (void) 0 \
)
#define MY_ASSERT_LOW(CONDITION) \
MY_ASSERT_IMPL(MY_ASSERT_COST_LOW, CONDITION)
#define MY_ASSERT_MEDIUM(CONDITION) \
MY_ASSERT_IMPL(MY_ASSERT_COST_MEDIUM, CONDITION)
#define MY_ASSERT_HIGH(CONDITION) \
MY_ASSERT_IMPL(MY_ASSERT_COST_HIGH, CONDITION)
#define MY_ASSERT_COST_NONE 0
#define MY_ASSERT_COST_LOW 1
#define MY_ASSERT_COST_MEDIUM 2
#define MY_ASSERT_COST_HIGH 3
#define MY_ASSERT_COST_ALL 10
#ifndef MY_ASSERT_COST_LIMIT
# define MY_ASSERT_COST_LIMIT MY_ASSERT_COST_MEDIUM
#endif
namespace my
{
[[noreturn]] extern void
assertion_failed(const char * filename, int line, const char * function,
const char * message) noexcept;
}
আপনি এখন তিনটি ম্যাক্রো ব্যবহার করতে পারেন MY_ASSERT_LOW
, MY_ASSERT_MEDIUM
এবং MY_ASSERT_HIGH
স্ট্যান্ডার্ড লাইব্রেরির পরিবর্তে "এক আকার সবই ফিট করে" assert
ম্যাক্রোর পরিবর্তে যেগুলি প্রভাবিত হয়, যথাক্রমে প্রভাবিত হয় না এবং তাদের ধারণকৃত কার্যকারিতাটির জটিলতাকে প্রাধান্য দেয় না। আপনি যখন সফ্টওয়্যারটি তৈরি করেন, আপনি প্রাক-প্রসেসরের প্রতীকটিকে MY_ASSERT_COST_LIMIT
নির্বাহযোগ্যর মধ্যে কী ধরনের যুক্তি তৈরি করতে হবে তা চয়ন করতে প্রাক-সংজ্ঞা দিতে পারেন। ধ্রুবকগুলি MY_ASSERT_COST_NONE
এবং MY_ASSERT_COST_ALL
কোনও দৃsert় ম্যাক্রোগুলির সাথে সামঞ্জস্য করে না এবং বোঝা যায় যে MY_ASSERT_COST_LIMIT
সমস্ত মানগুলি যথাক্রমে বন্ধ করতে বা যথাক্রমে মান হিসাবে ব্যবহৃত হবে।
আমরা এখানে অনুমানের উপর নির্ভর করছি যে একটি ভাল সংকলক এর জন্য কোনও কোড উত্পন্ন করবে না
if (false_constant_expression && run_time_expression) { /* ... */ }
এবং রূপান্তর
if (true_constant_expression && run_time_expression) { /* ... */ }
মধ্যে
if (run_time_expression) { /* ... */ }
যা আমি বিশ্বাস করি এটি আজকাল নিরাপদ অনুমান।
আপনি উপরের কোড খামচি সম্পর্কে হন, তাহলে মত কম্পাইলার-নির্দিষ্ট টীকা বিবেচনা __attribute__ ((cold))
উপর my::assertion_failed
বা __builtin_expect(…, false)
উপর !(CONDITION)
গৃহীত গবেষকেরা এর ভার হ্রাস করা সম্ভব হবে। রিলিজ বিল্ডসগুলিতে, আপনি ডায়াগনস্টিক বার্তা হারাতে অসুবিধার সময়ে পাদদেশ-মুদ্রণ হ্রাস করার my::assertion_failed
মতো কিছু দিয়ে ফাংশন কলটি প্রতিস্থাপনের বিষয়টি বিবেচনা করতে পারেন __builtin_trap
।
এই ধরণের অপ্টিমাইজেশানগুলি কেবলমাত্র খুব কমপ্যাক্ট এমন একটি ফাংশনে অত্যন্ত সস্তার দাবিতে (যেমন দুটি ইন্টিজারের সাথে ইতিমধ্যে যুক্তি হিসাবে দেওয়া হয়) তুলনায় প্রাসঙ্গিক, সমস্ত বার্তার স্ট্রিংগুলিকে সংহত করে বাইনারিগুলির অতিরিক্ত আকার বিবেচনা না করে।
এই কোডটি কীভাবে তুলনা করুন
int
positive_difference_1st(const int a, const int b) noexcept
{
if (!(a > b))
my::assertion_failed(__FILE__, __LINE__, __FUNCTION__, "!(a > b)");
return a - b;
}
নিম্নলিখিত সমাবেশে সংকলিত হয়
_ZN4test23positive_difference_1stEii:
.LFB0:
.cfi_startproc
cmpl %esi, %edi
jle .L5
movl %edi, %eax
subl %esi, %eax
ret
.L5:
subq $8, %rsp
.cfi_def_cfa_offset 16
movl $.LC0, %ecx
movl $_ZZN4test23positive_difference_1stEiiE12__FUNCTION__, %edx
movl $50, %esi
movl $.LC1, %edi
call _ZN2my16assertion_failedEPKciS1_S1_
.cfi_endproc
.LFE0:
যখন নিম্নলিখিত কোড
int
positive_difference_2nd(const int a, const int b) noexcept
{
if (__builtin_expect(!(a > b), false))
__builtin_trap();
return a - b;
}
এই সমাবেশ দেয়
_ZN4test23positive_difference_2ndEii:
.LFB1:
.cfi_startproc
cmpl %esi, %edi
jle .L8
movl %edi, %eax
subl %esi, %eax
ret
.p2align 4,,7
.p2align 3
.L8:
ud2
.cfi_endproc
.LFE1:
যা আমি অনেক বেশি স্বাচ্ছন্দ্য বোধ করি। (উদাহরণ ব্যবহার জিসিসি 5.3.0 সঙ্গে পরীক্ষা করা হয়েছিল -std=c++14
, -O3
এবং -march=native
4.3.3-2 আর্কিটেকচার, x86_64 গনুহ / লিনাক্স পতাকা। উপরে স্নিপেট দেখানো না ঘোষণা হয় test::positive_difference_1st
এবং test::positive_difference_2nd
যা আমি যোগ __attribute__ ((hot))
করতে। my::assertion_failed
সঙ্গে ঘোষণা করা হয় __attribute__ ((cold))
।)
তাদের উপর নির্ভর করে ফাংশনে পূর্বশর্তগুলি যুক্ত করুন
মনে করুন নির্দিষ্ট চুক্তি সহ আপনার নিম্নলিখিত ফাংশন রয়েছে।
/**
* @brief
* Counts the frequency of a letter in a string.
*
* The frequency count is case-insensitive.
*
* If `text` does not point to a NUL terminated character array or `letter`
* is not in the character range `[A-Za-z]`, the behavior is undefined.
*
* @param text
* text to count the letters in
*
* @param letter
* letter to count
*
* @returns
* occurences of `letter` in `text`
*
*/
std::size_t
count_letters(const char * text, int letter) noexcept;
লেখার বদলে
assert(text != nullptr);
assert((letter >= 'A' && letter <= 'Z') || (letter >= 'a' && letter <= 'z'));
const auto frequency = count_letters(text, letter);
প্রতিটি কল-সাইটে, যুক্তির সংজ্ঞাটি একবারে রাখুন count_letters
std::size_t
count_letters(const char *const text, const int letter) noexcept
{
assert(text != nullptr);
assert((letter >= 'A' && letter <= 'Z') || (letter >= 'a' && letter <= 'z'));
auto frequency = std::size_t {};
// TODO: Figure this out...
return frequency;
}
এবং এডো না করে এটিকে কল করুন।
const auto frequency = count_letters(text, letter);
এর নিম্নলিখিত সুবিধা রয়েছে।
- আপনাকে কেবল একবারের জন্য কোড লিখতে হবে। যেহেতু ফাংশনগুলির একেবারে উদ্দেশ্য তাদের বলা হয় - প্রায়শই একাধিক বার - এটি
assert
আপনার কোডের বিবৃতিগুলির সামগ্রিক সংখ্যা হ্রাস করতে হবে ।
- এটি যুক্তি রাখে যা পূর্বের শর্তাদি তাদের উপর নির্ভর করে যুক্তির নিকটে পরীক্ষা করে। আমি মনে করি এটি সবচেয়ে গুরুত্বপূর্ণ দিক। যদি আপনার ক্লায়েন্টরা আপনার ইন্টারফেসের অপব্যবহার করে তবে তারা সঠিকভাবে দৃ correctly়ভাবে প্রয়োগগুলি অনুমান করা যায় না যাতে ফাংশনটি তাদের জানায় এটি আরও ভাল।
সুস্পষ্ট অসুবিধাটি হ'ল আপনি ডায়াগনস্টিক বার্তায় কল-সাইটের উত্স অবস্থানটি পাবেন না। আমি বিশ্বাস করি এটি একটি ছোটখাটো সমস্যা। একটি ভাল ডিবাগার আপনাকে সুবিধামত চুক্তি লঙ্ঘনের মূলটি সনাক্ত করতে সক্ষম হতে হবে।
একই চিন্তা ওভারলোডেড অপারেটরগুলির মতো "বিশেষ" ফাংশনে প্রযোজ্য। যখন আমি পুনরাবৃত্তিগুলি লিখছি, আমি সাধারণত - যদি পুনরুক্তিকারী প্রকৃতি এটির অনুমতি দেয় - তাদের একটি সদস্য ফাংশন দিন
bool
good() const noexcept;
এটি পুনরুক্তিকারীকে ডিফারেন্স করা নিরাপদ কিনা তা জানতে সহায়তা করে। (অবশ্যই, বাস্তবে, এটির গ্যারান্টি দেওয়া প্রায় সবসময় সম্ভব যে এটি পুনরুক্তিকারীকে অবজ্ঞা করা নিরাপদ হবে না । তবে আমি বিশ্বাস করি যে আপনি এখনও এই জাতীয় কোনও ফাংশন দিয়ে প্রচুর বাগগুলি ধরতে পারেন)) আমার সমস্ত কোড লিটারের পরিবর্তে যে assert(iter.good())
স্টেটমেন্টগুলি দিয়ে পুনরুক্তি ব্যবহার করে , আমি তার পরিবর্তে পুনরুক্তির প্রয়োগের assert(this->good())
ক্ষেত্রে প্রথম লাইনের হিসাবে একটি একক রাখব operator*
।
আপনি যদি আপনার উত্স কোডটিতে পূর্ববর্তী শর্তাদি সম্পর্কে ম্যানুয়ালি জোর দেওয়ার পরিবর্তে মানক গ্রন্থাগারটি ব্যবহার করছেন তবে ডিবাগ বিল্ডগুলিতে তাদের চেকগুলি চালু করুন। তারা আরও বেশি পরিশীলিত চেক করতে পারে যেমন পরীক্ষার যে ধারকটি এখনও ব্যবহার করে তা এখনও বিদ্যমান কিনা তা পরীক্ষা করার জন্য। (আরও তথ্যের জন্য libstdc ++ এবং libc ++ (কাজ চলছে) এর জন্য ডকুমেন্টেশন দেখুন ))
ফ্যাক্টর সাধারণ পরিস্থিতি বাইরে
মনে করুন আপনি একটি লিনিয়ার বীজগণিত প্যাকেজ লিখছেন। অনেকগুলি কার্যক্রমে জটিল পূর্বশর্ত থাকতে হবে এবং সেগুলি লঙ্ঘন করার কারণে প্রায়শই ভুল ফলাফল ঘটে যা তত্ক্ষণাত্ সনাক্তযোগ্য নয়। এটি খুব ভাল হবে যদি এই ফাংশনগুলি তাদের পূর্বশর্তগুলি দৃ as় করে তোলে। আপনি যদি এমন একটি পূর্বাভাস সংজ্ঞায়িত করেন যা আপনাকে কোনও কাঠামোর বিষয়ে নির্দিষ্ট বৈশিষ্ট্যগুলি বলে দেয়, তবে সেগুলি আরও বেশি পাঠযোগ্য।
template <typename MatrixT>
auto
cholesky_decompose(MatrixT&& m)
{
assert(is_square(m) && is_symmetric(m));
// TODO: Somehow decompose that thing...
}
এটি আরও কার্যকর ত্রুটি বার্তা দেবে।
cholesky.hxx:357: cholesky_decompose: assertion failed: is_symmetric(m)
বলার চেয়ে অনেক বেশি সাহায্য করে
detail/basic_ops.hxx:1289: fast_compare: assertion failed: m(i, j) == m(j, i)
আপনাকে প্রথমে উত্সের কোডটি সন্ধান করতে হবে যেখানে প্রকৃতপক্ষে কী পরীক্ষা করা হয়েছিল তা নির্ধারণ করতে।
আপনার যদি class
অ-তুচ্ছ আক্রমণকারীদের সাথে থাকে, আপনি যখন অভ্যন্তরীণ অবস্থার সাথে গোলমাল করেছেন এবং সময় অনুযায়ী অবজেক্টটিকে কোনও বৈধ অবস্থায় রেখে দিচ্ছেন তা নিশ্চিত করার জন্য এটি সময়ে সময়ে তাদের উপর নির্ভর করা ভাল ধারণা to
এই উদ্দেশ্যে, আমি একটি private
সদস্য ফাংশন সংজ্ঞায়িত করতে দরকারী মনে করি যা আমি প্রচলিতভাবে কল করি class_invaraiants_hold_
। মনে করুন আপনি পুনরায় বাস্তবায়ন করছেন std::vector
(কারণ আমরা সকলেই জানি এটি যথেষ্ট ভাল নয়)), এটির মতো এটির কার্যকারিতা থাকতে পারে।
template <typename T>
bool
vector<T>::class_invariants_hold_() const noexcept
{
if (this->size_ > this->capacity_)
return false;
if ((this->size_ > 0) && (this->data_ == nullptr))
return false;
if ((this->capacity_ == 0) != (this->data_ == nullptr))
return false;
return true;
}
এ সম্পর্কে কয়েকটি বিষয় লক্ষ্য করুন।
- প্রেডিকেট ফাংশনটি নিজেই হয়
const
এবং noexcept
নির্দেশিকা অনুসারে যে দৃ .়বিশ্বাসের পার্শ্ব প্রতিক্রিয়া হবে না। যদি এটি বোধগম্য হয় তবে এটিও ঘোষণা করুন constexpr
।
- শিকারী কিছু নিজেই জোর দেয় না। এটি অভ্যন্তরীণ দৃ as়তা হিসাবে ডাকা যেতে বোঝানো হয় , যেমন
assert(this->class_invariants_hold_())
। এইভাবে, যদি দৃser়সংস্থানগুলি সংকলিত হয়, তবে আমরা নিশ্চিত হতে পারি যে কোনও রান-টাইম ওভারহেড ব্যয় করা হয়নি।
- ফাংশনের অভ্যন্তরে নিয়ন্ত্রণ প্রবাহটি একটি বৃহত প্রকাশের চেয়ে
if
প্রারম্ভিক return
গুলি সহ একাধিক বক্তব্যগুলিতে বিভক্ত হয় । এটি একটি ডিবাগারে ফাংশনটির মধ্য দিয়ে পদক্ষেপ নেওয়া সহজ করে তোলে এবং যদি দৃ fire়তা জানায় তবে আক্রমণকারীটির কোন অংশটি ভেঙে গেছে।
মূর্খ বিষয়গুলিতে দৃsert়তা দেবেন না
কিছু বিষয় কেবল দৃ to়তার সাথে বোঝায় না।
auto numbers = std::vector<int> {};
numbers.push_back(14);
numbers.push_back(92);
assert(numbers.size() == 2); // silly
assert(!numbers.empty()); // silly and redundant
এই দাবিগুলি কোডটি এমনকি একটি ছোট্ট আরও পড়তে পঠনযোগ্য বা তর্ক করার পক্ষে সহজ করে না। প্রতিটি সি ++ প্রোগ্রামারকে যথেষ্ট আত্মবিশ্বাসী হওয়া উচিত std::vector
যে উপরের কোডটি কেবল এটির দ্বারা দেখলে ঠিক করা যায় যে এটি নিশ্চিত হয়ে কাজ করে। আমি বলছি না যে আপনার কখনই কোনও ধারক আকারের উপর চাপ দেওয়া উচিত নয়। আপনি যদি কিছু অ-তুচ্ছ নিয়ন্ত্রণ প্রবাহ ব্যবহার করে উপাদানগুলি যোগ বা সরিয়ে থাকেন তবে এ জাতীয় দৃ an়তা কার্যকর হতে পারে। তবে এটি যদি কেবল উপরের-অ-দাবি-দাওয়ার কোডে যা লেখা হয়েছিল কেবল পুনরাবৃত্তি করে, কোনও মূল্য অর্জিত হয় না।
লাইব্রেরির ফাংশনগুলি সঠিকভাবে কাজ করে তা জোর করে বলবেন না।
auto w = widget {};
w.enable_quantum_mode();
assert(w.quantum_mode_enabled()); // probably silly
আপনি যদি গ্রন্থাগারটিকে অল্প বিশ্বাস করেন তবে এর পরিবর্তে অন্য একটি লাইব্রেরি ব্যবহার করা ভাল।
অন্যদিকে, লাইব্রেরির ডকুমেন্টেশন যদি 100% স্পষ্ট না হয় এবং উত্স কোডটি পড়ে আপনি এর চুক্তিগুলি সম্পর্কে আত্মবিশ্বাস অর্জন করেন, তবে "অনুমিত চুক্তি" হিসাবে দৃ to় ধারণা পোষণ করা অনেক অর্থবোধ করে। এটি যদি গ্রন্থাগারের ভবিষ্যতের সংস্করণে ভাঙা হয় তবে আপনি দ্রুত লক্ষ্য করবেন।
auto w = widget {};
// After reading the source code, I have concluded that quantum mode is
// always off by default but this isn't documented anywhere.
assert(!w.quantum_mode_enabled());
এটি নিম্নলিখিত সমাধানের চেয়ে ভাল যা আপনার অনুমানগুলি সঠিক ছিল কিনা তা আপনাকে জানায় না।
auto w = widget {};
if (w.quantum_mode_enabled())
{
// I don't think that quantum mode is ever enabled by default but
// I'm not sure.
w.disable_quantum_mode();
}
প্রোগ্রাম লজিক বাস্তবায়নের জন্য দৃ abuse়তা অবলম্বন করবেন না
আপনার অ্যাপ্লিকেশনটি তাত্ক্ষণিকভাবে হত্যার উপযুক্ত এমন বাগগুলি অনাবৃত করার জন্য দৃser় প্রতিবেদনগুলি ব্যবহার করা উচিত । সেগুলি অন্য কোনও শর্ত যাচাই করার জন্য ব্যবহার করা উচিত নয় এমনকি যদি সেই অবস্থার যথাযথ প্রতিক্রিয়াটি অবিলম্বে ত্যাগ করা হয়।
অতএব, এটি লিখুন ...
if (!server_reachable())
{
log_message("server not reachable");
shutdown();
}
…ঐটার পরিবর্তে.
assert(server_reachable());
অবিশ্বাস্য ইনপুটকে বৈধতা দেওয়ার জন্য কখনও কখনও দৃ use়তা ব্যবহার std::malloc
করবেন না বা যা আপনি করেননি তা পরীক্ষা return
করুন nullptr
। এমনকি যদি আপনি জানেন যে আপনি কখনও দৃ .়তা বন্ধ করবেন না, এমনকি রিলিজ বিল্ডেও, একটি প্রতিবেদন পাঠকের সাথে যোগাযোগ করে যে এটি এমন কিছু যাচাই করে যা প্রোগ্রামটি বাগ-মুক্ত রয়েছে এবং এটির কোনও দৃশ্যমান পার্শ্ব-প্রতিক্রিয়া নেই বলে সর্বদা সত্য cks আপনি যদি যোগাযোগ করতে চান এমন বার্তাটি না হয় তবে একটি বিকল্প ব্যর্থতা হ্যান্ডলিং প্রক্রিয়া যেমন throw
একটি ব্যতিক্রম আইএনএস ব্যবহার করুন । যদি আপনার অনাস্থা পরীক্ষার জন্য ম্যাক্রো মোড়ক দেওয়া আপনার পক্ষে সুবিধাজনক মনে হয় তবে একটি লেখার আগে এগিয়ে যান। কেবল এটিকে "দৃsert়বিশ্বাস", "অনুমান", "প্রয়োজনীয়তা", "নিশ্চিত" বা এর মতো কিছু বলবেন না। এর অভ্যন্তরীণ যুক্তিটি একই মত হতে পারে assert
, এটি ব্যতীত অবশ্যই কখনই সংকলিত হয় না।
অধিক তথ্য
আমি জন লাকোসের টক ডিফেন্সিভ প্রোগ্রামিং ডান রাইট পেয়েছি, এটি সিপিসি'ন 14 তে দেওয়া হয়েছে ( 1 ম অংশ , 2 তম অংশ ) খুব আলোকিত করে। আমি এই উত্তরে আমার চেয়ে আরও বেশি কীভাবে ব্যর্থতার ব্যতিক্রমগুলি সম্পর্কে প্রতিক্রিয়া জানাতে সক্ষম তা কী অনুকূলিতকরণের ধারণা নিয়েছে।